使用
@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错误配置。 我花了很多时间来调查细节,我的想法刚刚完成。 你认为我需要添加来构建一些缓存库或其他东西吗?
答案 0 :(得分:4)
这里有2个陷阱。
第一个是当使用hasRole('ADMIN')
时,首先检查是否以字符前缀(默认为ROLE_
)开头,否则传入的角色是前缀(另见reference guide)。因此,在这种情况下,检查的实际权限为ROLE_ADMIN
,而不是您期望/假设的ADMIN
。
第二个是当使用内存选项时,roles
方法与此处提到的相同。它检查传入的角色是否以角色前缀开头,如果没有,则添加它。因此,在包含内存的示例中,您最终会获得权限ROLE_ADMIN
和ROLE_DBA
。
但是,在JDBC选项中,您有权限ADMIN
和DBA
,因此hasRole('ADMIN')
检查失败,因为ROLE_ADMIN
不等于ADMIN
。
要解决此问题,您有多种选择。
hasRole
使用hasAuthority
后者不会添加角色前缀,而内存选项则使用authorities
而不是roles
。 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;
}
}
答案 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