自定义JdbcOAuth2AuthorizationService导致sid缺失及刷新令牌报错
我正在按照入门指南搭建Spring Authorization Server(依赖为org.springframework.boot:spring-boot-starter-oauth2-authorization-server:3.1.2),但当我定义如下OAuth2AuthorizationService Bean时:
@Bean public OAuth2AuthorizationService authorizationService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) { return new JdbcOAuth2AuthorizationService(jdbcOperations, registeredClientRepository); }
生成的id_token中缺少SessionId声明“sid”,导致使用刷新令牌获取新令牌时服务器抛出如下错误:
java.lang.IllegalArgumentException: value cannot be null at org.springframework.util.Assert.notNull(Assert.java:204) ~[spring-core-6.0.10.jar:6.0.10] at org.springframework.security.oauth2.jwt.JwtClaimsSet$Builder.claim(JwtClaimsSet.java:167) ~[spring-security-oauth2-jose-6.1.1.jar:6.1.1] at org.springframework.security.oauth2.server.authorization.token.JwtGenerator.generate(JwtGenerator.java:137) ~[spring-security-oauth2-authorization-server-1.1.1.jar:1.1.1] at org.springframework.security.oauth2.server.authorization.token.JwtGenerator.generate(JwtGenerator.java:60) ~[spring-security-oauth2-authorization-server-1.1.1.jar:1.1.1] at org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator.generate(DelegatingOAuth2TokenGenerator.java:59) ~[spring-security-oauth2-authorization-server-1.1.1.jar:1.1.1]
移除该Bean后,令牌中的“sid”声明能正确设置。我使用JdbcOAuth2AuthorizationService将授权信息存储到数据库以实现授权服务器的水平扩展,请问是否遗漏了什么配置?
问题出在自定义JdbcOAuth2AuthorizationService时,未完整配置配套的持久化组件,导致会话ID(sid)无法被正确持久化和读取。默认的内存实现会自动维护会话关联信息,但切换到JDBC存储后需要手动补充相关配置:
步骤1:确保数据库表结构正确
Spring Authorization Server的JDBC实现依赖特定的数据库表,需提前创建:oauth2_authorization:存储授权会话、令牌等核心信息,其中包含会话ID相关字段oauth2_authorization_consent:存储用户对客户端的授权同意记录
这些表的结构需符合官方定义的规范,确保字段完整才能正常存储sid。
步骤2:注册配套的
JdbcOAuth2AuthorizationConsentService
仅注册授权服务的JDBC实现是不完整的,需要同时注册授权同意服务的JDBC实现,保证授权数据的完整链路:@Bean public OAuth2AuthorizationConsentService authorizationConsentService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) { return new JdbcOAuth2AuthorizationConsentService(jdbcOperations, registeredClientRepository); }步骤3:在授权服务器安全链中关联自定义授权服务
配置SecurityFilterChain时,需明确将自定义的OAuth2AuthorizationService绑定到授权服务器配置中:@Bean @Order(1) public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, OAuth2AuthorizationService authorizationService) throws Exception { OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); http.getConfigurer(OAuth2AuthorizationServerConfigurer.class) .authorizationService(authorizationService); // 关联自定义授权服务 return http.build(); }步骤4:自定义JwtGenerator确保sid声明被添加
如果上述配置后仍存在sid缺失问题,可以自定义JwtGenerator,手动从授权信息中提取sid并添加到JWT声明:@Bean public JwtGenerator jwtGenerator(JwtEncoder jwtEncoder, OAuth2AuthorizationService authorizationService) { JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder); jwtGenerator.setJwtClaimsSetCustomizer((context) -> { OAuth2Authorization authorization = context.getAuthorization(); String sid = authorization.getAttribute(OAuth2AuthorizationAttributeNames.SESSION_ID); if (sid != null) { context.getClaims().claim("sid", sid); } }); return jwtGenerator; }
内容的提问来源于stack exchange,提问作者DarkImage

