spring security oauth2.x迁移到spring security5.x - 客户端(单点登录)
差异
- 废弃@EnableOAuth2Client注解,改为使用oauth2Client方法
- 废弃@EnableOAuth2Sso注解,改为使用oauth2Login方法
- 废弃OAuth2RestTemplate,可OAuth2AuthorizedClientService来获取token,用以实现RestTemplate interceptor或WebClient exchange filter function传播token
- 废弃OAuth2ClientContext,oauth2上下文信息不再保存在MVC会话中,而通过仓库OAuth2AuthorizedClientRepository保存,可通过方法参数注解@RegisteredOAuth2AuthorizedClient获取当前授权的客户端对象
- 通过ClientRegistrationRepository来提供复数客户端,而不再通过配置文件配置单一的客户端。
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
配置
spring:
security:
oauth2:
client:
registration:
my-auth-code:
provider: my-auth
client-id: client-id
client-secret: client-secret
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/psr-auth-code"
scope: all
provider:
my-auth:
authorization-uri: http://localhost/oauth/authorize
token-uri: http://localhost/oauth/token
user-info-uri: http://localhost/oauth/check_user
userNameAttribute: username
@Configuration
protected static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
http.oauth2Client();
http.oauth2Login();
}
}
注意事项
- 以默认配置启用oauth2登录时,需要将跳转url设为如下形式
{baseUrl}/login/oauth2/code/registration-id
否则在授权服务器登陆成功后跳转回客户端站点无法完成认证授权,将再次跳转到授权服务器登陆界面
默认oauth2登录配置源码
public OAuth2LoginConfigurer<HttpSecurity> oauth2Login() throws Exception {
return (OAuth2LoginConfigurer)this.getOrApply(new OAuth2LoginConfigurer());
}
org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurer
private String loginProcessingUrl = "/login/oauth2/code/*";
public void init(B http) throws Exception {
OAuth2LoginAuthenticationFilter authenticationFilter = new OAuth2LoginAuthenticationFilter(OAuth2ClientConfigurerUtils.getClientRegistrationRepository((HttpSecurityBuilder)this.getBuilder()), OAuth2ClientConfigurerUtils.getAuthorizedClientRepository((HttpSecurityBuilder)this.getBuilder()), this.loginProcessingUrl);
this.setAuthenticationFilter(authenticationFilter);
}
- 如果用spring-session-data-redis等管理分布式会话,需要配置使用JdbcOAuth2AuthorizedClientService或者自定义分布式的客户端授权信息服务。
否则会导致多实例或者重启客户端服务时,用户会话已认证授权但是无法获取token的情况。
因为oauth上下文不再保存在会话对象中,默认配置是通过InMemoryOAuth2AuthorizedClientService保存和加载客户端授权信息。
默认oauth2客户端配置源码
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2WebSecurityConfiguration
@Bean
@ConditionalOnMissingBean
OAuth2AuthorizedClientService authorizedClientService(ClientRegistrationRepository clientRegistrationRepository) {
return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
}
- 不再支持无有效期的token?如果授权服务器客户端信息没有配置token超时时间,则默认的有效期到token订阅时间+1秒
默认oauth2访问token响应解析源码
org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse
private Instant getIssuedAt() {
if (this.issuedAt == null) {
this.issuedAt = Instant.now();
}
return this.issuedAt;
}
private Instant getExpiresAt() {
if (this.expiresAt == null) {
Instant issuedAt = getIssuedAt();
this.expiresAt = (this.expiresIn > 0) ? issuedAt.plusSeconds(this.expiresIn) : issuedAt.plusSeconds(1);
}
return this.expiresAt;
}
源码
- 客户端注册信息
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientRegistrationRepositoryConfiguration
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(OAuth2ClientProperties.class)
@Conditional(ClientsConfiguredCondition.class)
class OAuth2ClientRegistrationRepositoryConfiguration {
@Bean
@ConditionalOnMissingBean(ClientRegistrationRepository.class)
InMemoryClientRegistrationRepository clientRegistrationRepository(OAuth2ClientProperties properties) {
List<ClientRegistration> registrations = new ArrayList<>(
OAuth2ClientPropertiesRegistrationAdapter.getClientRegistrations(properties).values());
return new InMemoryClientRegistrationRepository(registrations);
}
}