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
- Access client1
- client1 directs requests to sso-server
- Agree to authorize
- Return client1 with authorization code
- client1 holds the authorization code request token
- Return the JWT token
- client1 parses tokens and logs in
- client1 accesses client2
- client2 directs requests to sso-server
- Agree to authorize
- Return client2 with authorization code
- client2 requests the token with the authorization code
- Return the JWT token
- 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
Code download
Download it from my github. https://github.com/longfeizheng/sso-merryyou