Implementation of SSO with Spring Cloud-OAuth2 and zuul

Preface

After climbing for two days, the pit finally came up. It was very simple to see what others wrote. When they wrote, they had various problems. There were many SSO articles on the Internet, and when they wrote, they had various problems (they were too dishy). Make a note. It's easy to check later.

For the OAuth2 Authentication and Authorization Server, see the previous article

https://zcsherrydc.github.io/2019/10/07/SpringCloud-OAuth2%E5%92%8CJWT/

<font color=ff> project address </font>:

https://github.com/zcsherrydc/SpringCloudStudy Using git tools

git checkout sso

reference material:

https://www.cnblogs.com/cjsblog/p/10548022.html

Ruan Yifeng's OAuth 2 Explanation https://blog.csdn.net/WSM960921/article/details/98222004

What is SSO?

English full name single Sign On, Chinese list login. In a multi-application system, users only need to log in once to access all trust services. SSO solves the problem of accessing user session s from other services without login by mapping user login information to browser cookie s.

General framework

There are five modules in one project:

  • oauth-server is an authentication and authorization service responsible for token issuance

  • zuul is a gateway service to achieve unified authorization

  • Eureka-client and eureka-client 1 are two application services

  • eureka-server-single is the eureka registry

To achieve the function is to access eureka-client through zuul port, first need to log in, then jump to oauth-server to authenticate and authorize, after success, you can also access eureka-client 1 without login.

oauth-server

See for details

https://zcsherrydc.github.io/2019/10/07/SpringCloud-OAuth2%E5%92%8CJWT/

Changed several places

AuthorizationServerConfig

   @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("zuul")
                .secret(new BCryptPasswordEncoder().encode("secret"))
                .scopes("app")
                .authorizedGrantTypes("authorization_code", "password")
                .redirectUris("http://localhost:9110/login")
        ;
//        clients.withClientDetails(new JdbcClientDetailsService(dataSource));
    }

UserController

This function provides validation for other module resource servers

@RestController
@RequestMapping("/oauth2_token")
public class UserController {
    @GetMapping("/current")
    public Principal user(Principal principal) {
        return principal;
    }
}

ResourceServerConfig

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
//                AnMatcher indicates that requests for / oauth2_token can only be processed
                .antMatcher("/oauth2_token/**")
                .authorizeRequests()
                .anyRequest().authenticated()
        ;
    }

application.yml

Add the root address, that is, add / oauth-server every time you visit the service

server:
  port: 9120
#  invalid_token error is reported if the url root address is not configured
#  Or you can configure it in zuul
  servlet:
    context-path: /oauth-server

Zuul

zuul serves as the entrance of the system, providing routing, unified authorization and other functions.

Dependencies are shown in the project

<font color='red'> Note: All modules introduce spring-cloud-starter-oauth2 dependencies, so they are put into the project's public pom.xml. To achieve oauth2, only one reference is needed to </font>.

application.yml

Post out the main configuration as detailed in the project

sensitiveHeaders: This must be done. zuul rewrites the header information in the request when forwarding the route. Setting it to empty is no filtering.

security.oauth2.resource: This is the configuration associated with parsing tokens

Resource servers need to parse tokens to verify correctness in three ways:

  1. If the token is not jwt asymmetric encryption, then access / oauth/check_token verifies token directly. If it is asymmetric, access / oauth/token_key to obtain the public key for parsing
  2. Access the method in the controller of the authentication server and get Principal to verify it
  3. Locally configure the resource server, inherit the ResourceServer Configurer Adapter interface, and implement the same encryption method as the authentication server.
zuul:
  routes:
    eureka-client:
      path: /eureka-client/**
      sensitiveHeaders:
      serviceId: eureka-client
    eureka-client1:
      path: /eureka-client1/**
      sensitiveHeaders:
      serviceId: eureka-client1
    oauth-server:
      path: /oauth-server/**
      sensitiveHeaders:
        serviceId: eureka-client
#Authentication server address
oauth-server: http://localhost:9120/oauth-server
security:
  oauth2:
#   Corresponding to the client setting in the authentication server  
    client:
	  client-id: zuul
      client-secret: secret
#	   Get the token address
      access-token-uri: ${oauth-server}/oauth/token
#      Authentication address
      user-authorization-uri: ${oauth-server}/oauth/authorize
    resource:
#      Perform token verification
#      1. Access controller to get Principal
#      user-info-uri: ${oauth-server}/oauth2_token/current
#      prefer-token-info: false
#      Accessing Authorization Server to Obtain Public Key Resolution Token
      jwt:
        key-uri: ${oauth-server}/oauth/token_key

Configure Web Security Config

The entire zuul module can be added with this configuration

@EnableOAuth2Sso
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        //URLs requiring authorization    
                .authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and().csrf().disable()
        ;
    }
}

eureka-client (resource server)

application.yml

Add the following to verify that the requested token is correct

security:
  oauth2:
    resource:
      id: eureka-client
      #      Three authentication token methods for resource server
      #       Local configuration in ResourceServer Config
      #      2. Get the user information from the authentication server and resolve the token
      #      user-info-uri: ${oauth-server}/oauth2_token/current
      #      prefer-token-info: false
      #       3. Remotely Acquiring Public Key Resolution token
      jwt:
        key-uri: ${oauth-server}/oauth/token_key

Configure ResourceServer Config

The resource server only needs to add this configuration.

@Configuration
@EnableResourceServer
//Spring Security disables annotations by default and opens annotations here
// Combining @PreAuthorize("hasRole('admin')) to determine whether a user has access to a method at a control layer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
//                Configure URLs that require permissions
                .authorizeRequests()
                .anyRequest().authenticated()
                .and().csrf().disable();
        ;
    }

    //The following is the local method of token validation. If you use this method, comment out the configuration of the above application.yml and put oauth2.jks in the resources folder
//    @Override
//    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
//        resources.resourceId("app").tokenStore(tokenStore());
//    }
//
//    @Bean
//    public TokenStore tokenStore() {
//        return new JwtTokenStore(jwtAccessTokenConverter());
//    }
//
//    /**
//     * Signature of token by asymmetric encryption algorithm
//     *
//     * @return
//     */
//    @Bean
//    public JwtAccessTokenConverter jwtAccessTokenConverter() {
//        final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
//        // Import Certificate
//        KeyStoreKeyFactory keyStoreKeyFactory =
//                new KeyStoreKeyFactory(new ClassPathResource("oauth2.jks"), "mypass".toCharArray());
//        converter.setKeyPair(keyStoreKeyFactory.getKeyPair("oauth2"));
//        return converter;
//    }
}

<font color='red'>Note: </font>

If you use local validation methods, you may not be able to report an error reading oauth2.jks, because by default you do not refer to files in the resources directory and you need to add configuration under < build > in pom.xml

        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>

test

Start order:

  • eureka-server-single
  • oauth-server
  • zuul
  • eureka-client and eureka-ciient1

Access method under eureka-client through zuul port http://localhost:9110/eureka-client/hi

It will automatically jump to the login page of oauth-server and enter the username and password to login.

Look at url, jump to oauth/authorize, which is the authorization interface, and then carry some zuul configuration information.

Success

Accessing eureka-client 1 does not require login

summary

It's concise, but it really took two days to make it (it's still too good).

There is no literary grace, and the principled things can not be written out. We can only record the practice, and we can communicate with each other.

See Personal Blog for more articles https://zcsherrydc.github.io/

Keywords: Programming github git Spring xml

Added by gbrown on Fri, 11 Oct 2019 14:13:16 +0300