不久前,我创建了一个 Spring Book 应用程序,它使用 Okta 作为 OIDC 提供程序。它基于 Matt Raible 的这个伟大示例的先前版本。
我现在要做的是获取登录用户的组或角色。
Matt 回复Spring Boot / Okta - 如何检索用户组说我应该向 Okta 接口添加声明,我已经这样做了。
他限定了它,说
然后,如果您使用 Okta Spring Boot 启动器,您的组将自动转换为 Spring Security 权限。
我转换为 Spring Boot 入门套件,步骤如下:
将入门工具包添加到 pom.xml
更改了应用程序属性以使用入门工具包中的变量,如下所示:
#okta spring boot starter kit
okta.oauth2.issuer=https://dev-xxxx.okta.com/oauth2/default
okta.oauth2.audience=api://default
okta.oauth2.groupsClaim=groups
#okta spring boot starter kit test
okta.oauth2.clientId=xxxxxxxxxxxx
okta.oauth2.clientSecret=xxxxxxxxxxxxxxxxx
它的工作原理和以前一样。
但是,当我打印权限时,我仍然看不到这些组。我看到的唯一权威是这个:
权限:ROLE_USER 用户名:[email protected]
这是打印权限的代码:
Collection<? extends GrantedAuthority> authorities = principal.getAuthorities();
for (GrantedAuthority authority : authorities) {
System.out.println("Authority: " + authority.getAuthority());
}
我在这里做错了什么吗?
我认为添加
groupsClaim
属性会自动将值映射到权限。您确定要将其添加到 ID 令牌吗?
以下技术是我们在 JHipster 中使用的技术,它使用 Spring Security 而不使用 Okta 启动器。
在安全配置中添加一个
GrantedAuthoritiesMapper
bean。
/**
* Map authorities from "groups" or "roles" claim in ID Token.
*
* @return a {@link GrantedAuthoritiesMapper} that maps groups from
* the IdP to Spring Security Authorities.
*/
@Bean
public GrantedAuthoritiesMapper userAuthoritiesMapper() {
return (authorities) -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
authorities.forEach(authority -> {
// Check for OidcUserAuthority because Spring Security 5.2 returns
// each scope as a GrantedAuthority, which we don't care about.
if (authority instanceof OidcUserAuthority) {
OidcUserAuthority oidcUserAuthority = (OidcUserAuthority) authority;
mappedAuthorities.addAll(SecurityUtils.extractAuthorityFromClaims(oidcUserAuthority.getUserInfo().getClaims()));
}
});
return mappedAuthorities;
};
}
来自
SecurityUtils
的相关方法有:
public static List<GrantedAuthority> extractAuthorityFromClaims(Map<String, Object> claims) {
return mapRolesToGrantedAuthorities(getRolesFromClaims(claims));
}
@SuppressWarnings("unchecked")
private static Collection<String> getRolesFromClaims(Map<String, Object> claims) {
return (Collection<String>) claims.getOrDefault("groups",
claims.getOrDefault("roles",
claims.getOrDefault(CLAIMS_NAMESPACE + "roles", new ArrayList<>())));
}
private static List<GrantedAuthority> mapRolesToGrantedAuthorities(Collection<String> roles) {
return roles.stream()
.filter(role -> role.startsWith("ROLE_"))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}