版本
1.2.1
定制方法
默认用户信息Mapper只针对用户ID,电子邮件,电话,个人档案等字段进行处理,如需在用户信息端点返回自定义的字段可通过以下方法定制Mapper
代码语言:javascript复制@Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtTokenCustomizer() {
return (context) -> {
if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) {
context.getClaims().claims((claims) -> {
// 在令牌中添加了角色声明信息,默认用户信息端点Mapper不会进行处理
Set<String> roles = AuthorityUtils.authorityListToSet(context.getPrincipal().getAuthorities())
.stream()
.map(c -> c.replaceFirst("^ROLE_", ""))
.collect(Collectors.collectingAndThen(Collectors.toSet(), Collections::unmodifiableSet));
claims.put("roles", roles);
});
}
};
}
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(
HttpSecurity http
) {
...
// 定制Mapper
Function<OidcUserInfoAuthenticationContext, OidcUserInfo> userInfoMapper = (context) -> {
OidcUserInfoAuthenticationToken authentication = context.getAuthentication();
JwtAuthenticationToken principal = (JwtAuthenticationToken) authentication.getPrincipal();
// 解析JWT令牌中的所有声明信息
return new OidcUserInfo(principal.getToken().getClaims());
};
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
// 启用OpenID Connect 1.0
.oidc(oidc->{
oidc.userInfoEndpoint(userInfo->{
userInfo.userInfoMapper(userInfoMapper);
});
});
}
源码
userInfoMapper 默认配置
- OpenID Connect 用户信息认证器 org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcUserInfoAuthenticationProvider
public final class OidcUserInfoAuthenticationProvider implements AuthenticationProvider {
...
// 用户信息Mapper默认值
private Function<OidcUserInfoAuthenticationContext, OidcUserInfo> userInfoMapper = new DefaultOidcUserInfoMapper();
...
private static final class DefaultOidcUserInfoMapper implements Function<OidcUserInfoAuthenticationContext, OidcUserInfo> {
// 电子邮件声明字段
private static final List<String> EMAIL_CLAIMS = Arrays.asList(
StandardClaimNames.EMAIL,
StandardClaimNames.EMAIL_VERIFIED
);
// 电话声明字段
private static final List<String> PHONE_CLAIMS = Arrays.asList(
StandardClaimNames.PHONE_NUMBER,
StandardClaimNames.PHONE_NUMBER_VERIFIED
);
// 个人档案声明字段
private static final List<String> PROFILE_CLAIMS = Arrays.asList(
StandardClaimNames.NAME,
StandardClaimNames.FAMILY_NAME,
StandardClaimNames.GIVEN_NAME,
StandardClaimNames.MIDDLE_NAME,
StandardClaimNames.NICKNAME,
StandardClaimNames.PREFERRED_USERNAME,
StandardClaimNames.PROFILE,
StandardClaimNames.PICTURE,
StandardClaimNames.WEBSITE,
StandardClaimNames.GENDER,
StandardClaimNames.BIRTHDATE,
StandardClaimNames.ZONEINFO,
StandardClaimNames.LOCALE,
StandardClaimNames.UPDATED_AT
);
@Override
public OidcUserInfo apply(OidcUserInfoAuthenticationContext authenticationContext) {
OAuth2Authorization authorization = authenticationContext.getAuthorization();
OidcIdToken idToken = authorization.getToken(OidcIdToken.class).getToken();
OAuth2AccessToken accessToken = authenticationContext.getAccessToken();
// 获取scope请求的声明信息
Map<String, Object> scopeRequestedClaims = getClaimsRequestedByScope(idToken.getClaims(),
accessToken.getScopes());
// 使用请求的声明信息创建用户信息对象
return new OidcUserInfo(scopeRequestedClaims);
}
private static Map<String, Object> getClaimsRequestedByScope(Map<String, Object> claims, Set<String> requestedScopes) {
Set<String> scopeRequestedClaimNames = new HashSet<>(32);
// 用户ID
scopeRequestedClaimNames.add(StandardClaimNames.SUB);
// 根据请求的SCOPE添加字段
if (requestedScopes.contains(OidcScopes.ADDRESS)) {
scopeRequestedClaimNames.add(StandardClaimNames.ADDRESS);
}
if (requestedScopes.contains(OidcScopes.EMAIL)) {
scopeRequestedClaimNames.addAll(EMAIL_CLAIMS);
}
if (requestedScopes.contains(OidcScopes.PHONE)) {
scopeRequestedClaimNames.addAll(PHONE_CLAIMS);
}
if (requestedScopes.contains(OidcScopes.PROFILE)) {
scopeRequestedClaimNames.addAll(PROFILE_CLAIMS);
}
// 根据请求的SCOPE字段过滤信息
Map<String, Object> requestedClaims = new HashMap<>(claims);
requestedClaims.keySet().removeIf(claimName -> !scopeRequestedClaimNames.contains(claimName));
return requestedClaims;
}
}
}
- OpenID Connect 用户信息端点配置器 org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OidcUserInfoEndpointConfigurer
public final class OidcUserInfoEndpointConfigurer extends AbstractOAuth2Configurer {
...
// userInfoMapper配置入口
public OidcUserInfoEndpointConfigurer userInfoMapper(
Function<OidcUserInfoAuthenticationContext, OidcUserInfo> userInfoMapper) {
this.userInfoMapper = userInfoMapper;
return this;
}
...
// 初始化安全配置
@Override
void init(HttpSecurity httpSecurity) {
// 应用用户信息端点URI安全配置
AuthorizationServerSettings authorizationServerSettings = OAuth2ConfigurerUtils.getAuthorizationServerSettings(httpSecurity);
String userInfoEndpointUri = authorizationServerSettings.getOidcUserInfoEndpoint();
this.requestMatcher = new OrRequestMatcher(
new AntPathRequestMatcher(userInfoEndpointUri, HttpMethod.GET.name()),
new AntPathRequestMatcher(userInfoEndpointUri, HttpMethod.POST.name()));
// 应用用户认证器
List<AuthenticationProvider> authenticationProviders = createDefaultAuthenticationProviders(httpSecurity);
if (!this.authenticationProviders.isEmpty()) {
authenticationProviders.addAll(0, this.authenticationProviders);
}
this.authenticationProvidersConsumer.accept(authenticationProviders);
authenticationProviders.forEach(authenticationProvider ->
httpSecurity.authenticationProvider(postProcess(authenticationProvider)));
}
// 创建 OpenID Connect 用户信息认证器
private List<AuthenticationProvider> createDefaultAuthenticationProviders(HttpSecurity httpSecurity) {
List<AuthenticationProvider> authenticationProviders = new ArrayList<>();
OidcUserInfoAuthenticationProvider oidcUserInfoAuthenticationProvider =
new OidcUserInfoAuthenticationProvider(
OAuth2ConfigurerUtils.getAuthorizationService(httpSecurity));
// 如果存在定制的userInfoMapper,则替换默认值
if (this.userInfoMapper != null) {
oidcUserInfoAuthenticationProvider.setUserInfoMapper(this.userInfoMapper);
}
authenticationProviders.add(oidcUserInfoAuthenticationProvider);
return authenticationProviders;
}
}