Spring Security source code analysis 12: Spring Security OAuth2 implements single sign-on based on JWT

Single sign -on (English: Single sign-on, abbreviated as SSO), also translated as single sign-in, is a property that provides access control for many interrelated but independent software systems. With this attribute, when a user logs in, they can gain access to all systems instead of logging in to each single system. This functionality is usually implemented using the Lightweight Directory Access Protocol (LDAP), where user information is stored in an LDAP database on the server. Similarly, single sign-off means that only a single sign-off action is required to end access to multiple systems.

Security OAuth2 single sign-on process diagram

https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/SpringSecurity-OAuth2-sso.png

  1. access client1
  2. client1direct the requestsso-server
  3. consent to authorization
  4. codeReturn with the authorization codeclient1
  5. client1Hold the authorization code to request the token
  6. return JWTtoken
  7. client1Parse the token and log in
  8. client1accessclient2
  9. client2direct the requestsso-server
  10. consent to authorization
  11. codeReturn with the authorization codeclient2
  12. client2Hold the authorization code to request the token
  13. return JWTtoken
  14. client2Parse the token and log in

The user's login status is sso-serversaved by the authentication center, and the authentication of the login interface and account password is also done by the sso-serverauthentication center (it is different from client1the clien2return token, but the parsed user information is the same user ).

Security OAuth2 implements single sign-on

Project structure

https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth2-sso01.png

sso-server

Authentication server

@Configuration
@EnableAuthorizationServer
public class SsoAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    /**
     * 客户端一些配置
     * @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");
    }

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

    /**
     * springSecurity 授权表达式,访问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());
    }

    /**
     * 生成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地址
server:
  context-path: /client1
  port: 8083
security:
  oauth2:
    client:
      client-id: merryyou1
      client-secret: merryyousecrect1
      user-authorization-uri: ${auth-server}/oauth/authorize #请求认证的地址
      access-token-uri: ${auth-server}/oauth/token #请求令牌的地址
    resource:
      jwt:
        key-uri: ${auth-server}/oauth/token_key #解析jwt令牌所需要密钥的地址

sso-client2

Same as sso-client1

The effect is as follows:https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth2-sso01.gif

code download

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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324434329&siteId=291194637