使用 Spring Boot 的角色层次结构和 OAuth2 安全性

Posted

技术标签:

【中文标题】使用 Spring Boot 的角色层次结构和 OAuth2 安全性【英文标题】:Role hierarchy and OAuth2 Security using Spring Boot 【发布时间】:2017-08-07 23:47:58 【问题描述】:

我知道有很多关于角色层次结构的线程,但是我找不到任何与 OAuth2 结合的示例。

所以, 大多数线程都指向我需要实现RoleHierarchy bean:

Beans.java

@EnableJpaRepositories(basePackages = "com.template.service.repository")
@EnableAspectJAutoProxy
@ComponentScan
@Configuration
public class Beans 
@Bean
public ItemService itemsService(ItemsRepository itemsRepository) 
    return new ItemService(itemsRepository);


@Bean
public RoleHierarchy roleHierarchy()
    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
    roleHierarchy.setHierarchy("ROLE_SUPREME > ROLE_DEVELOPER ROLE_DEVELOPER > ROLE_ADMIN  ROLE_ADMIN > ROLE_USER");
    return roleHierarchy;


@Bean
public DtoMapper dtoMapper() 
    return new DtoMapper();


接下来,我需要 @Autowire 这个 bean 到我的 WebSecurityConfigurerAdapter。但是因为我使用的是 OAuth2 安全性,所以我在 ResourceServerConfigurerAdapter 内部配置了 HttpSecurity

OAuth2.java

public class OAuth2 
@EnableAuthorizationServer
@Configuration
@ComponentScan
public static class AuthorizationServer extends AuthorizationServerConfigurerAdapter 

    @Autowired
    private AuthenticationManager authenticationManagerBean;
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception 
        clients.inMemory()
                .withClient("trusted_client")
                .authorizedGrantTypes("password", "refresh_token")
                .scopes("read", "write");
    

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception 
        endpoints.authenticationManager(authenticationManagerBean).userDetailsService(userDetailsService);
    

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception 
        security.allowFormAuthenticationForClients();
    


@EnableResourceServer
@Configuration
@ComponentScan
public static class ResourceServer extends ResourceServerConfigurerAdapter 

    @Autowired
    private RoleHierarchy roleHierarchy;

    private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() 
        OAuth2WebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new OAuth2WebSecurityExpressionHandler();
        defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy);
        return defaultWebSecurityExpressionHandler;
    

    @Override
    public void configure(HttpSecurity http) throws Exception 
        http
                .authorizeRequests().expressionHandler(webExpressionHandler())
                .antMatchers("/api/**").hasRole("DEVELOPER");
    


Security.java

@EnableWebSecurity
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@Configuration
@ComponentScan
public class Security extends WebSecurityConfigurerAdapter 

@Autowired
private UserDetailsService userDetailsService;

@Bean
public JpaAccountDetailsService userDetailsService(AccountsRepository accountsRepository) 
    return new JpaAccountDetailsService(accountsRepository);


@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception 
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());


@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception 
    return super.authenticationManagerBean();


@Bean
public PasswordEncoder passwordEncoder()
    return new BCryptPasswordEncoder();
 

但是层次结构不起作用。带有 SUPREME 用户凭据的请求以:


  "error": "access_denied",
  "error_description": "Access is denied"

当我将 hasRole("DEVELOPER") 切换到 hasRole("SUPREME") 时 - 一切正常。

我正在使用 Spring Boot 1.5.2 和 Spring Security OAuth 2.1.0.RELEASE

更新

当我评论所有 OAuth2.java 类并将 webExpressionHandler() 方法签名移动到 Security.java 类时 - 角色层次结构工作正常。那么 OAuth2 资源服务器是怎么回事呢?

【问题讨论】:

【参考方案1】:

您如何看待 ResourceServer 中的这种方法?

   @Bean
    public RoleHierarchyImpl roleHierarchy() 
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        roleHierarchy.setHierarchy("ROLE_SUPREME > ROLE_DEVELOPER ROLE_DEVELOPER > ROLE_ADMIN  ROLE_ADMIN > ROLE_USER")         return roleHierarchy;
    


    @Bean
    public RoleHierarchyVoter roleVoter() 
        return new RoleHierarchyVoter(roleHierarchy());
    


    @Bean
    public AffirmativeBased defaultOauthDecisionManager(RoleHierarchy roleHierarchy) //

      List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();

      // webExpressionVoter
      OAuth2WebSecurityExpressionHandler expressionHandler = new OAuth2WebSecurityExpressionHandler();
      expressionHandler.setRoleHierarchy(roleHierarchy);
      WebExpressionVoter webExpressionVoter = new WebExpressionVoter();
      webExpressionVoter.setExpressionHandler(expressionHandler);
      decisionVoters.add(webExpressionVoter);
      decisionVoters.add(roleVoter());
      return new AffirmativeBased(decisionVoters);
    

还有

http
                .authorizeRequests()
                .accessDecisionManager(defaultOauthDecisionManager(roleHierarchy()))
                //etc...

它可以更好地结构化和封装,但你知道我的意思,不是吗?...我认为它工作得很好。我希望这会对你有所帮助...

【讨论】:

【参考方案2】:

这样就成功了。我已经测试过了。

ROLE_SUPREME > ROLE_DEVELOPER > ROLE_ADMIN

代码博客如下

@Bean
public static RoleHierarchyImpl roleHierarchy() 

    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
    roleHierarchy.setHierarchy("ROLE_SUPREME > ROLE_DEVELOPER > ROLE_ADMIN ");
    return roleHierarchy;


希望对你有所帮助。

【讨论】:

以上是关于使用 Spring Boot 的角色层次结构和 OAuth2 安全性的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security 3.2 - 配置全局方法安全性以使用角色层次结构

Spring security @secure 不适用于角色层次结构

Java:Spring security 3 角色层次结构

如何让jsp中的spring安全角色层次结构起作用?

Spring Webflux Security 中的角色层次结构

Spring Security 3.1.4 taglib 授权/身份验证不适用于 Tomcat 7 上 JSF 2.2 中的角色层次结构