spring security oauth2.x迁移到spring security5.x - 客户端(单点登录)

官方迁移指引
官方文档

差异

  1. 废弃@EnableOAuth2Client注解,改为使用oauth2Client方法
  2. 废弃@EnableOAuth2Sso注解,改为使用oauth2Login方法
  3. 废弃OAuth2RestTemplate,可OAuth2AuthorizedClientService来获取token,用以实现RestTemplate interceptor或WebClient exchange filter function传播token
  4. 废弃OAuth2ClientContext,oauth2上下文信息不再保存在MVC会话中,而通过仓库OAuth2AuthorizedClientRepository保存,可通过方法参数注解@RegisteredOAuth2AuthorizedClient获取当前授权的客户端对象
  5. 通过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);
	}

}

posted on 2022-04-11 22:38  路过君  阅读(470)  评论(0编辑  收藏  举报

导航