Spring security jdbcAuthentication 不适用于默认角色处理

Ser*_*gii 4 security authentication spring jdbc role

使用

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

我的例子效果很好。例如对于

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

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

    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
         auth.jdbcAuthentication().dataSource(dataSource);
Run Code Online (Sandbox Code Playgroud)

我确信我使用 spring 建议配置了数据库和架构(以便能够使用默认的 jdbc 身份验证)。

在调试模式下,我可以看到从数据库加载的结果

org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl
    #loadUserByUsername(username)[line 208]
    return createUserDetails(username, user, dbAuths);
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

M. *_*num 6

这里有两个陷阱。

第一个是,当hasRole('ADMIN')首先使用它时,会检查它是否以角色前缀(默认为ROLE_)开头,如果传入的角色不是以它为前缀(另请参阅参考指南)。因此,在这种情况下,检查的实际权限ROLE_ADMIN并不ADMIN像您期望/假设的那样。

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

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

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

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

使用hasAuthority

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

auth.inMemoryAuthentication()
    .withUser("dba").password("root123")
    .authorities("ADMIN","DBA");
Run Code Online (Sandbox Code Playgroud)

接下来也改变一下你的表情

.antMatchers("/db/**").access("hasAuthority('ADMIN') and hasAuthority('DBA')")
Run Code Online (Sandbox Code Playgroud)

前缀为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;
    }
}
Run Code Online (Sandbox Code Playgroud)