Spring Authorization Server:授权范围未出现在令牌及context.getAuthorizations()中
核心问题是OAuth2Authorization对象的authorizedScopes未被正确持久化到数据库,导致令牌自定义器中无法获取已同意的范围,同时数据库中授权条目的accessTokenScopes字段为空。虽然授权端点的Authentication对象包含正确范围,但这些范围未被关联到OAuth2Authorization并保存。
1. 修正数据库表结构(使用默认JDBC存储时)
如果使用官方提供的JdbcOAuth2AuthorizationService,需确保oauth2_authorization表包含access_token_scopes字段,用于存储访问令牌的范围。若表结构缺失该字段,执行以下SQL补充(以MySQL为例):
ALTER TABLE oauth2_authorization ADD COLUMN access_token_scopes VARCHAR(1000) DEFAULT NULL;
该字段会自动存储逗号分隔的范围字符串,Spring Authorization Server会将authorizedScopes序列化为对应值。
2. 自定义OAuth2AuthorizationGenerator绑定范围
若默认授权生成逻辑未将同意范围关联到OAuth2Authorization,自定义OAuth2AuthorizationGenerator强制注入范围:
@Bean public OAuth2AuthorizationGenerator authorizationGenerator(OAuth2AuthorizationRepository authorizationRepository) { DefaultOAuth2AuthorizationGenerator generator = new DefaultOAuth2AuthorizationGenerator(authorizationRepository); generator.setAuthorizationCustomizer((authorizationBuilder, context) -> { // 获取用户已同意的范围 Set<String> authorizedScopes = context.getAuthorizedScopes(); // 绑定到OAuth2Authorization authorizationBuilder.authorizedScopes(authorizedScopes); // 同步设置访问令牌的范围 authorizationBuilder.accessToken(tokenBuilder -> tokenBuilder.scopes(authorizedScopes)); }); return generator; }
该逻辑会在授权对象生成阶段,将同意范围显式绑定到OAuth2Authorization,确保持久化后可被正确读取。
3. 临时绕过方案(直接从Authentication提取范围)
若需快速实现令牌中添加范围的需求,可直接从Authentication对象提取范围:
import java.util.Set; import java.util.stream.Collectors; @Bean public OAuth2TokenCustomizer<JwtEncodingContext> oAuth2TokenCustomizer() { return context -> { // 提取以SCOPE_前缀开头的权限,转换为范围字符串 Set<String> scopes = context.getAuthentication().getAuthorities().stream() .map(authority -> authority.getAuthority()) .filter(auth -> auth.startsWith("SCOPE_")) .map(auth -> auth.substring("SCOPE_".length())) .collect(Collectors.toSet()); context.getClaims().claim("authorities", scopes); }; }
注意:这是临时方案,建议优先解决OAuth2Authorization的持久化问题,保证授权数据一致性。
4. 检查授权同意配置
若RegisteredClient设置了requireAuthorizationConsent(true),需确保用户在授权页面明确同意了请求的范围;若设置为false,Spring Authorization Server会自动授权所有请求范围,需确保这些范围被同步到OAuth2Authorization中。
内容的提问来源于stack exchange,提问作者Colin Riddell

