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
- access client1
client1
direct the requestsso-server
- consent to authorization
code
Return with the authorization codeclient1
client1
Hold the authorization code to request the token- return
JWT
token client1
Parse the token and log inclient1
accessclient2
client2
direct the requestsso-server
- consent to authorization
code
Return with the authorization codeclient2
client2
Hold the authorization code to request the token- return
JWT
token client2
Parse the token and log in
The user's login status is sso-server
saved by the authentication center, and the authentication of the login interface and account password is also done by the sso-server
authentication center (it is different from client1
the clien2
return token
, but the parsed user information is the same user ).
Security OAuth2 implements single sign-on
Project structure
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
code download
Download from my github, https://github.com/longfeizheng/sso-merryyou