【问题标题】:Spring security jdbcAuthentication does not work with default roles processingSpring security jdbcAuthentication 不适用于默认角色处理
【发布时间】:2016-06-23 23:34:18
【问题描述】:

使用

    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
         auth.inMemoryAuthentication().withUser("dba").password("root123").roles("ADMIN","DBA");

我的示例运行良好。例如对于

      http.authorizeRequests()
        // ...
        .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
        .and().formLogin()
        .and().exceptionHandling().accessDeniedPage("/Access_Denied");

如果我将 inMemoryAuthentication 更改为 spring jdbc 默认值 - 我遇到了角色问题。

    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
         auth.jdbcAuthentication().dataSource(dataSource);

我确定我使用 spring 推荐配置了 db 和 schema(能够使用默认的 jdbc 身份验证)。

在调试模式下,我可以在

中看到从 db 加载的结果
org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl
    #loadUserByUsername(username)[line 208]
    return createUserDetails(username, user, dbAuths);

它返回与内存配置类似的结果:

org.springframework.security.core.userdetails.User@183a3:
     Username: dba;
     Password: [PROTECTED];
     Enabled: true;
     AccountNonExpired: true;
     credentialsNonExpired: true;
     AccountNonLocked: true;
     Granted Authorities: ADMIN,DBA

如您所见,它加载了相应的授权权限,但 http 请求将我重定向到 .accessDeniedPage("/Access_Denied")。我很困惑,因为它应该像以前一样适用于用户。

我的项目中没有使用 Spring Boot。 我的日志不包含任何 jdbc 错误配置。 我花了很多时间研究细节,我的想法刚刚完成。 你认为我需要添加来构建一些缓存库或其他东西吗?

【问题讨论】:

  • 不,它不应该...当使用 in-memroy 数据库时,角色会自动以ROLE_ 为前缀(默认角色前缀)。 hasRole('ADMIN') 也是如此,它还将检查传入的角色是否带有前缀,如果没有,则添加它。您的用户拥有ADMIN 而不是ROLE_ADMIN 的权限,因此检查失败。要么使用 hasAuthority 而不是 hasRole (并在你的内存样本中将 roles 更改为 authorities )或在数据库中的权限前加上 ROLE_ 或将默认角色前缀更改为空而不是ROLE_.
  • 非常感谢!现在可以了。您能否在角色比较的位置添加链接(我希望这些信息在不久的将来对我有用)?

标签: spring security authentication jdbc role


【解决方案1】:

您可以看到启用日志记录发生了什么。在你的application.properties 添加:

# ==============================================================
# = Logging springframework
# ==============================================================
logging.level.org.springframework.jdbc=DEBUG
logging.level.org.springframework.security=DEBUG
logging.level.org.springframework.web=DEBUG
logging.level.org.springframework.http=DEBUG

【讨论】:

    【解决方案2】:

    这里有两个陷阱。

    首先,当使用hasRole('ADMIN')时,首先检查它是否以角色前缀(默认为ROLE_)开头,如果不是,则传入的角色是前缀(另见@ 987654321@)。所以在这种情况下,检查的实际权限是ROLE_ADMIN,而不是您期望/假设的ADMIN

    第二个是当使用内存选项时,roles 方法的作用与这里提到的相同。它检查传入的角色是否以角色前缀开头,如果不是则添加它。因此,在您的带有内存的示例中,您最终会得到权威ROLE_ADMINROLE_DBA

    但是,在您的 JDBC 选项中,您有权限 ADMINDBA,因此 hasRole('ADMIN') 检查失败,因为 ROLE_ADMIN 不等于 ADMIN

    要解决此问题,您有多种选择。

    1. 而不是hasRole 使用hasAuthority,后者不添加角色前缀,并且对于内存选项使用authorities 而不是roles
    2. 在 JDBC 选项中为数据库中的权限添加前缀ROLE_
    3. 将默认角色前缀设置为空。

    使用hasAuthority

    首先将内存数据库的配置更改为使用authorities 而不是roles

    auth.inMemoryAuthentication()
        .withUser("dba").password("root123")
        .authorities("ADMIN","DBA");
    

    接下来也要改变你的表达方式

    .antMatchers("/db/**").access("hasAuthority('ADMIN') and hasAuthority('DBA')")
    

    前缀为ROLE_

    在插入权限的脚本中,在权限前加上ROLE_

    移除默认角色前缀

    这有点棘手,在 [迁移指南] 中有详细描述。

    没有简单的配置选项,需要BeanPostProcessor

    public class DefaultRolesPrefixPostProcessor implements BeanPostProcessor, PriorityOrdered {
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName)
                throws BeansException {
    
            // remove this if you are not using JSR-250
            if(bean instanceof Jsr250MethodSecurityMetadataSource) {
                ((Jsr250MethodSecurityMetadataSource) bean).setDefaultRolePrefix(null);
            }
    
            if(bean instanceof DefaultMethodSecurityExpressionHandler) {
                ((DefaultMethodSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
            }
            if(bean instanceof DefaultWebSecurityExpressionHandler) {
                ((DefaultWebSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
            }
            if(bean instanceof SecurityContextHolderAwareRequestFilter) {
                ((SecurityContextHolderAwareRequestFilter)bean).setRolePrefix("");
            }
            return bean;
        }
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName)
                throws BeansException {
            return bean;
        }
    
        @Override
        public int getOrder() {
            return PriorityOrdered.HIGHEST_PRECEDENCE;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-31
      • 2021-05-05
      • 2016-05-30
      • 2014-11-13
      • 1970-01-01
      相关资源
      最近更新 更多