基于角色的授权:使用 OneLogin 和 Spring Security 的 Oauth

Posted

技术标签:

【中文标题】基于角色的授权:使用 OneLogin 和 Spring Security 的 Oauth【英文标题】:Role based authorization: Oauth with OneLogin and Spring Security 【发布时间】:2021-02-15 02:21:38 【问题描述】:

我有一个 Spring Boot 应用程序,它使用 Oauth 和 OneLogin 作为授权服务器。 现在,我想实现基于角色的授权,以便仅将某些 API 公开给具有某些特权的用户。

我有属于组的用户。假设用户 A 属于“admin”组,而用户 B 不属于 admin 组。我的问题是如何使用这些组来仅允许用户 A 访问某些 API。

这是认证用户的参考信息:

authorities 
0   
authority   "ROLE_USER"           **//says ROLE_USER even when the user belongs to the admin group** 
attributes  
at_hash "xxxxx"
sub "xxxx"
iss "https://******/oidc/2"
groups  
0   "Group A"
1   "Group B"
2   **"DEMO"**
3   **"DEMO Admin"**               **//presence in this group should be considered for authorisation**
preferred_username  "xxx"
given_name  "xxxx"
nonce   "xxxxxxx"
sid "xxxxxxx"
aud 
0   "xxxxxxx"
updated_at  "xxxxxx"
name    "xxxxxx"
exp "xxxxxxx"
family_name "xxxxxx"
iat "xxxxxxxx"
email   "xxxxxxxx"
idToken …
userInfo    …
1   
authority   "SCOPE_email"
2   
authority   "SCOPE_groups"
3   
authority   "SCOPE_openid"
4   
authority   "SCOPE_profile"

我想像这样保护我的休息控制器:

@PreAuthorize("Belongs to group admin")
@RequestMapping(value = "/delete", method = RequestMethod.GET)
public string delete() 
  System.out.println("delete");

这是我的 application.yaml 文件

server:
  servlet:
    context-path: /demo


spring:
  security:
    oauth2:
      client:
        registration:
          onelogin:
            client-id: *****
            client-secret: *******
            scope: openid,profile,email,groups
            provider: onelogin
        provider:
          onelogin:
            issuer-uri: https://******/oidc/2

【问题讨论】:

我是否正确理解您的应用程序既是 OAuth2 客户端又是资源服务器? 是的。没错! 【参考方案1】:

由于您的应用程序也是资源服务器,因此您可以使用自定义 JwtAuthenticationConverter 来配置 JWT 如何转换为 Authentication 对象。针对这种情况,您可以配置 JWT 如何转换为GrantedAuthorities 列表。

默认情况下,资源服务器根据"scope" 声明填充GrantedAuthorities。 如果 JWT 包含名称为 "scope""scp" 的声明,则 Spring Security 将使用该声明中的值通过在每个值前面加上 "SCOPE_" 来构造权限。这就是为什么您会看到权威机构“SCOPE_email”、“SCOPE_groups”等

如果您想根据“组”声明填充GrantedAuthorities,您可以这样做:

@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() 
    JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
    converter.setJwtGrantedAuthoritiesConverter(new CustomJwtGrantedAuthoritiesConverter());
    return converter;


public class CustomJwtGrantedAuthoritiesConverter implements Converter<Jwt, Collection<GrantedAuthority>> 
    @Override
    public Collection<GrantedAuthority> convert(Jwt jwt) 
        Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        for (String group : getGroups(jwt)) 
            grantedAuthorities.add(new SimpleGrantedAuthority(group));
        
        return grantedAuthorities;
    


private Collection<String> getGroups(Jwt jwt) 
    Object groups = jwt.getClaim("groups");
    // Convert groups to Collection of Strings based on your logic

然后您可以使用表达式"hasAuthority('YOUR_CUSTOM_GROUP_NAME')" 来限制对某些端点的访问。

【讨论】:

感谢您的回答。但是当我添加您的转换器代码时出现以下错误。 org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration 中的方法 springSecurityFilterChain 需要一个找不到的 'org.springframework.security.oauth2.jwt.JwtDecoder' 类型的 bean。 您还需要在资源服务器中设置issuer-uri。 YML 与您目前拥有的非常相似。查看文档docs.spring.io/spring-security/site/docs/current/reference/… 中的此部分

以上是关于基于角色的授权:使用 OneLogin 和 Spring Security 的 Oauth的主要内容,如果未能解决你的问题,请参考以下文章

使用 Keycloak 和 .NET 核心的基于角色的授权

IdentityServer4 基于角色的授权

graphql 基于角色的授权

如何根据 HTTP 请求方法使用 Apache Shiro 进行基于角色的授权

基于角色的授权 Django/Graphql/Apollo/Vue

使用 IdentityServer4 对 Web API 进行基于角色的授权