Spring安全性jdbcAuthentication不适用于默认角色处理

时间:2016-03-09 14:22:14

标签: spring security authentication jdbc role

使用

    @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 default - 我遇到了角色问题而不是。

    @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错误配置。 我花了很多时间来调查细节,我的想法刚刚完成。 你认为我需要添加来构建一些缓存库或其他东西吗?

2 个答案:

答案 0 :(得分:4)

这里有2个陷阱。

第一个是当使用hasRole('ADMIN')时,首先检查是否以字符前缀(默认为ROLE_)开头,否则传入的角色是前缀(另见reference guide)。因此,在这种情况下,检查的实际权限为ROLE_ADMIN,而不是您期望/假设的ADMIN

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

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

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

  1. 而不是hasRole使用hasAuthority后者不会添加角色前缀,而内存选项则使用authorities而不是roles
  2. 在JDBC选项中,使用ROLE_
  3. 为数据库中的权限添加前缀
  4. 将默认角色前缀设置为空。
  5. 使用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;
        }
    }
    

答案 1 :(得分:0)

您可以看到启用日志记录时发生了什么。在您的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