Spring security jdbcAuthentication 不适用于默认角色处理
Spring security jdbcAuthentication does not work with default roles processing
使用
@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 建议配置了数据库和架构(以便能够使用默认的 jdbc 身份验证)。
在调试模式下,我可以在
中看到从数据库加载的结果
org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl
#loadUserByUsername(username)[line 208]
return createUserDetails(username, user, dbAuths);
它 returns 与内存配置类似的结果:
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 引导。
我的日志不包含任何 jdbc 错误的配置。
我花了很多时间调查细节,我的想法才刚刚完成。
你认为我需要添加以构建一些缓存库或其他东西吗?
这里有 2 个陷阱。
首先是当使用 hasRole('ADMIN')
时,首先检查它是否以角色前缀(默认为 ROLE_
)开头,如果不是,则传入的角色前缀为 with它(另见 reference guide)。所以在这种情况下,实际检查的权限是 ROLE_ADMIN
而不是 ADMIN
,就像你 expect/assume。
第二个是当使用内存选项时,roles
方法与此处提到的相同。它检查传入的角色是否以角色前缀开头,如果不是则添加它。因此,在内存中的示例中,您最终获得了权限 ROLE_ADMIN
和 ROLE_DBA
。
然而,在您的 JDBC 选项中,您拥有权限 ADMIN
和 DBA
,因此 hasRole('ADMIN')
检查失败,因为 ROLE_ADMIN
不等于 ADMIN
。
要修复您有多种选择。
- 而不是
hasRole
使用 hasAuthority
后者不添加角色前缀并且对于内存选项使用 authorities
而不是 roles
。
- 在 JDBC 选项中,数据库中的权限前缀为
ROLE_
- 将默认角色前缀设置为空。
使用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;
}
}
您可以看到启用日志记录发生了什么。在您的 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
使用
@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 建议配置了数据库和架构(以便能够使用默认的 jdbc 身份验证)。
在调试模式下,我可以在
中看到从数据库加载的结果org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl
#loadUserByUsername(username)[line 208]
return createUserDetails(username, user, dbAuths);
它 returns 与内存配置类似的结果:
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 引导。 我的日志不包含任何 jdbc 错误的配置。 我花了很多时间调查细节,我的想法才刚刚完成。 你认为我需要添加以构建一些缓存库或其他东西吗?
这里有 2 个陷阱。
首先是当使用 hasRole('ADMIN')
时,首先检查它是否以角色前缀(默认为 ROLE_
)开头,如果不是,则传入的角色前缀为 with它(另见 reference guide)。所以在这种情况下,实际检查的权限是 ROLE_ADMIN
而不是 ADMIN
,就像你 expect/assume。
第二个是当使用内存选项时,roles
方法与此处提到的相同。它检查传入的角色是否以角色前缀开头,如果不是则添加它。因此,在内存中的示例中,您最终获得了权限 ROLE_ADMIN
和 ROLE_DBA
。
然而,在您的 JDBC 选项中,您拥有权限 ADMIN
和 DBA
,因此 hasRole('ADMIN')
检查失败,因为 ROLE_ADMIN
不等于 ADMIN
。
要修复您有多种选择。
- 而不是
hasRole
使用hasAuthority
后者不添加角色前缀并且对于内存选项使用authorities
而不是roles
。 - 在 JDBC 选项中,数据库中的权限前缀为
ROLE_
- 将默认角色前缀设置为空。
使用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;
}
}
您可以看到启用日志记录发生了什么。在您的 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