SpringBoot实现一个简单的SSO单点登录
Spring Boot开发一个平台,提供一套标准的接入规则第三方系统按照这个规则接入之后从平台进入第三方系统的时候实现免登陆进入,这种情况常见的解决方案有就是单点登录(SSO)操作,可以通过OAuth 2.0协议实现。下面我们就来看看如何使用Spring Boot和OAuth 2.0来实现单点登录操作。
搭建认证服务器
首先,我们可以使用Spring Authorization Server来搭建一个简单的授权认证的服务器。如下所示先要引入相关的POM依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
<version>0.2.3</version>
</dependency>
配置认证服务器
我们可以创建一个AuthServerConfig配置类来对OAuth2认证服务进行配置,充当认证服务器,如下所示。
@Configuration
@EnableWebSecurity
@EnableAuthorizationServer
@EnableResourceServer
public class AuthServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login", "/oauth/authorize").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
@Bean
public UserDetailsService userDetailsService() {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
return new InMemoryUserDetailsManager(
User.withUsername("user")
.password(encoder.encode("password"))
.roles("USER")
.build());
}
@Bean
public ClientDetailsService clientDetailsService() {
BaseClientDetails client = new BaseClientDetails();
client.setClientId("client-id");
client.setClientSecret("client-secret");
client.setAuthorizedGrantTypes(Arrays.asList("authorization_code", "refresh_token"));
client.setScope(Arrays.asList("read", "write"));
return new InMemoryClientDetailsService(client);
}
}
配置第三方系统
配置完成之后,接下来就是需要第三方系统进行接入了,然后可以保证第三方系统可以通过这个认证服务器来验证JWT的令牌操作如下所示。先要引入安全认证相关的POM依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
配置资源服务器
接下来就是来创建一个资源配置的服务器用来进行第三方资源的配置,如下所示。
@Configuration
@EnableWebSecurity
@EnableResourceServer
public class ResourceServerConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/public").permitAll()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
@Bean
public JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(publicKey()).build();
}
// 在这里加载你的公钥
private RSAPublicKey publicKey() {
// 从文件或配置中加载公钥
}
}
配置平台访问第三方系统
在我们搭建的SSO平台应用中,当用户需要访问第三方应用程序的时候,在平台中需要获取到一个OAuth 2.0令牌,然后在请求中携带这个令牌开始请求,如下所示。
@RestController
@RequestMapping("/third-party")
public class ThirdPartyController {
private final OAuth2AuthorizedClientService authorizedClientService;
public ThirdPartyController(OAuth2AuthorizedClientService authorizedClientService) {
this.authorizedClientService = authorizedClientService;
}
@GetMapping
public String accessThirdParty(@RegisteredOAuth2AuthorizedClient("client-id") OAuth2AuthorizedClient authorizedClient) {
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
String tokenValue = accessToken.getTokenValue();
// 使用RestTemplate或WebClient来访问第三方系统,并附带令牌
// RestTemplate restTemplate = new RestTemplate();
// HttpHeaders headers = new HttpHeaders();
// headers.setBearerAuth(tokenValue);
// HttpEntity<String> entity = new HttpEntity<>(headers);
// ResponseEntity<String> response = restTemplate.exchange("http://third-party-system/api", HttpMethod.GET, entity, String.class);
// return response.getBody();
return "Access token: " + tokenValue;
}
}
这样就可以实现一个简单的SSO单点登录了,用户从当前平台访问第三方系统时,就可以携带OAuth 2.0令牌进行免登录访问了。
总结
通过这种方式就可以利用OAuth 2.0协议实现从当前平台访问第三方系统的免登录。而在整个过程中涉及到了认证服务器、配置系统JWT,以及在平台中获取到令牌去访问第三方系统。整个过程实现都相对比较简单,但是在实际生产环境中,我们处于对安全性的考虑,还需要处理