Spring Security Source Analysis 12: Spring Security OAuth2 Single Sign-on Based on JWT

Keywords: github Java Spring Session

Single sign on (English: Single sign-on, abbreviated as SSO), also translated as a single check-in, which provides access control attributes for many interrelated but independent software systems. When the user logs in, he can gain access to all the systems without having to log in to each single system one by one. This function is usually implemented by the Light Directory Access Protocol (LDAP), which stores user information in the LDAP database on the server. Similarly, single sign-off means that access to multiple systems can be terminated with a single sign-off action.

Security OAuth2 Single Sign-on Process Diagram

  1. Access client1
  2. client1 directs requests to sso-server
  3. Agree to authorize
  4. Return client1 with authorization code
  5. client1 holds the authorization code request token
  6. Return the JWT token
  7. client1 parses tokens and logs in
  8. client1 accesses client2
  9. client2 directs requests to sso-server
  10. Agree to authorize
  11. Return client2 with authorization code
  12. client2 requests the token with the authorization code
  13. Return the JWT token
  14. client2 parses tokens and logs in

The user's login status is saved by sso-server authentication center, and the authentication of login interface and account password is also done by sso-server authentication center (client1 and clien2 return token are different, but the parsed user information is the same user).

Implementation of Single Sign-on in Security OAuth2

Project structure

sso-server

Authentication Server

@Configuration
@EnableAuthorizationServer
public class SsoAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    /**
     * Some client configurations
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("merryyou1")
                .secret("merryyousecrect1")
                .authorizedGrantTypes("authorization_code", "refresh_token")
                .scopes("all")
                .and()
                .withClient("merryyou2")
                .secret("merryyousecrect2")
                .authorizedGrantTypes("authorization_code", "refresh_token")
                .scopes("all");
    }

    /**
     * Configure jwttokenStore
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(jwtTokenStore()).accessTokenConverter(jwtAccessTokenConverter());
    }

    /**
     * springSecurity Authorization expression, which requires authentication when accessing merryyou tokenkey
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("isAuthenticated()");
    }

    /**
     * JWTtokenStore
     * @return
     */
    @Bean
    public TokenStore jwtTokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    /**
     * Generating JTW token
     * @return
     */
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("merryyou");
        return converter;
    }
}

security configuration

@Configuration
public class SsoSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin().loginPage("/authentication/require")
                .loginProcessingUrl("/authentication/form")
                .and().authorizeRequests()
                .antMatchers("/authentication/require",
                        "/authentication/form",
                        "/**/*.js",
                        "/**/*.css",
                        "/**/*.jpg",
                        "/**/*.png",
                        "/**/*.woff2"
                )
                .permitAll()
                .anyRequest().authenticated()
                .and()
                .csrf().disable();
//        http.formLogin().and().authorizeRequests().anyRequest().authenticated();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
}

SsoUserDetailsService

@Component
public class SsoUserDetailsService implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return new User(username, passwordEncoder.encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
    }
}

application.yml

server:
  port: 8082
  context-path: /uaa
spring:
  freemarker:
    allow-request-override: false
    allow-session-override: false
    cache: true
    charset: UTF-8
    check-template-location: true
    content-type: text/html
    enabled: true
    expose-request-attributes: false
    expose-session-attributes: false
    expose-spring-macro-helpers: true
    prefer-file-system-access: true
    suffix: .ftl
    template-loader-path: classpath:/templates/

sso-client1

SsoClient1Application

@SpringBootApplication
@RestController
@EnableOAuth2Sso
public class SsoClient1Application {

    @GetMapping("/user")
    public Authentication user(Authentication user) {
        return user;
    }

    public static void main(String[] args) {
        SpringApplication.run(SsoClient1Application.class, args);
    }
}

application.yml

auth-server: http://Localhost: 8082/uaa sso-server address
server:
  context-path: /client1
  port: 8083
security:
  oauth2:
    client:
      client-id: merryyou1
      client-secret: merryyousecrect1
      user-authorization-uri: ${auth-server}/oauth/authorize #Address Requesting Authentication
      access-token-uri: ${auth-server}/oauth/token #The address of the request token
    resource:
      jwt:
        key-uri: ${auth-server}/oauth/token_key #Address of key needed to parse jwt token

sso-client2

Consistent with sso-client 1

The results are as follows:

Code download

Download it from my github. https://github.com/longfeizheng/sso-merryyou

Posted by crusty_php on Wed, 09 Jan 2019 23:54:10 -0800