前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring security authorization server 定制令牌和用户信息

spring security authorization server 定制令牌和用户信息

作者头像
路过君
发布2024-01-05 08:47:03
1720
发布2024-01-05 08:47:03
举报

版本

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
代码语言:javascript
复制
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
代码语言:javascript
复制
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;
	}
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-01-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 版本
  • 定制方法
  • 源码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档