【发布时间】:2017-06-16 05:37:00
【问题描述】:
我无法在 @PreAuthorize 注释中使用 hasRole 方法。 request.isUserInRole(“ADMIN”) 也提供 false。我错过了什么?
虽然.hasAuthority(“ADMIN”) 工作正常。
我正在为数据库中的用户分配权限。
【问题讨论】:
标签: spring-boot spring-security
我无法在 @PreAuthorize 注释中使用 hasRole 方法。 request.isUserInRole(“ADMIN”) 也提供 false。我错过了什么?
虽然.hasAuthority(“ADMIN”) 工作正常。
我正在为数据库中的用户分配权限。
【问题讨论】:
标签: spring-boot spring-security
您必须使用前缀ROLE_ 命名您的权限才能使用isUserInRole,请参阅Spring Security Reference:
HttpServletRequest.isUserInRole(String) 将确定
SecurityContextHolder.getContext().getAuthentication().getAuthorities()是否包含GrantedAuthority,并将角色传递给isUserInRole(String)。通常,用户不应将“ROLE_”前缀传递给此方法,因为它是自动添加的。例如,如果要确定当前用户是否具有“ROLE_ADMIN”权限,可以使用以下命令:boolean isAdmin = httpServletRequest.isUserInRole("ADMIN");
hasRole(也称为hasAnyRole)相同,参见Spring Security Reference:
如果当前主体具有指定角色,则返回
true。默认情况下,如果提供的角色不以“ROLE_”开头,它将被添加。这可以通过修改DefaultWebSecurityExpressionHandler上的defaultRolePrefix来定制。
【讨论】:
我不得不即兴发挥一点,也许还有其他比我更简单的方法,但在我研究这个的时候,我别无选择,只能即兴发挥一点,经过彻底的研究提出了这个解决方案。
Spring Security 有一个名为AccessDecisionManager 的接口,您需要实现它。
@Component
public class RolesAccessDecisionManager implements AccessDecisionManager {
private final static String AUTHENTICATED = "authenticated";
private final static String PERMIT_ALL = "permitAll";
@Override
public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
collection.forEach(configAttribute -> {
if (!this.supports(configAttribute))
throw new AccessDeniedException("ACCESS DENIED");
});
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.isAuthenticated()) {
String rolesAsString = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining(","));
if (configAttribute.toString().contains(rolesAsString))
return true;
else
return (configAttribute.toString().contains(PERMIT_ALL) || configAttribute.toString().contains(AUTHENTICATED));
}
return true;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
现在要使用您的安全配置支持此自定义访问决策管理器,请在安全配置中执行以下操作:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
// other configs
.accessDecisionManager(this.accessDecisionManager)
accessDecisionManager 是您创建的 AccessDecisionManager 实现的自动装配 bean。
【讨论】:
您可以使用hasRole() 或hasAuthority()。不同之处在于,您必须使用ROLE_ 才能使用hasAusthority() 方法。
所以对于ROLE_ADMIN,
@PreAuthorize("hasRole('ADMIN')") == @PreAuthorize("hasAuthority('ROLE_ADMIN')")
【讨论】: