如何使用Spring Security在Java代码中检查“hasRole”?
如何检查Java代码中的用户权限或权限? 例如 – 我想根据angular色显示或隐藏用户的button。 有如下注释:
@PreAuthorize("hasRole('ROLE_USER')")
如何使用Java代码? 就像是 :
if(somethingHere.hasRole("ROLE_MANAGER")) { layout.addComponent(new Button("Edit users")); }
Spring Security 3.0有这个API
SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)
您可以使用HttpServletRequest对象的isUserInRole方法。
就像是:
public String createForm(HttpSession session, HttpServletRequest request, ModelMap modelMap) { if (request.isUserInRole("ROLE_ADMIN")) { // code here } }
而不是使用循环来从UserDetails中find权限,你可以这样做:
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); boolean authorized = authorities.contains(new SimpleGrantedAuthority("ROLE_ADMIN"));
您可以检索安全上下文,然后使用它:
import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; protected boolean hasRole(String role) { // get security context from thread local SecurityContext context = SecurityContextHolder.getContext(); if (context == null) return false; Authentication authentication = context.getAuthentication(); if (authentication == null) return false; for (GrantedAuthority auth : authentication.getAuthorities()) { if (role.equals(auth.getAuthority())) return true; } return false; }
你可以像下面那样实现一个hasRole()方法 – (这是在Spring 3.0.x上testing的,不知道其他版本)
protected final boolean hasRole(String role) { boolean hasRole = false; UserDetails userDetails = getUserDetails(); if (userDetails != null) { Collection<GrantedAuthority> authorities = userDetails.getAuthorities(); if (isRolePresent(authorities, role)) { hasRole = true; } } return hasRole; } /** * Get info about currently logged in user * @return UserDetails if found in the context, null otherwise */ protected UserDetails getUserDetails() { Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); UserDetails userDetails = null; if (principal instanceof UserDetails) { userDetails = (UserDetails) principal; } return userDetails; } /** * Check if a role is present in the authorities of current user * @param authorities all authorities assigned to current user * @param role required authority * @return true if role is present in list of authorities assigned to current user, false otherwise */ private boolean isRolePresent(Collection<GrantedAuthority> authorities, String role) { boolean isRolePresent = false; for (GrantedAuthority grantedAuthority : authorities) { isRolePresent = grantedAuthority.getAuthority().equals(role); if (isRolePresent) break; } return isRolePresent; }
我正在使用这个:
@RequestMapping(method = RequestMethod.GET) public void welcome(SecurityContextHolderAwareRequestWrapper request) { boolean b = request.isUserInRole("ROLE_ADMIN"); System.out.println("ROLE_ADMIN=" + b); boolean c = request.isUserInRole("ROLE_USER"); System.out.println("ROLE_USER=" + c); }
来自JoseK的答案不能用在你的服务层,在那里你不想引入与HTTP请求引用的web层的耦合。 如果您正在寻求解决服务层中的angular色问题,Gopi的答案就是要走的路。
但是,这有点长。 可以从authentication中直接访问权限。 因此,如果你可以假设你有一个用户login,下面是它:
/** * @return true if the user has one of the specified roles. */ protected boolean hasRole(String[] roles) { boolean result = false; for (GrantedAuthority authority : SecurityContextHolder.getContext().getAuthentication().getAuthorities()) { String userRole = authority.getAuthority(); for (String role : roles) { if (role.equals(userRole)) { result = true; break; } } if (result) { break; } } return result; }
奇怪的是,我不认为这个问题有一个标准的解决scheme,因为spring-security访问控制是基于expression式的 ,而不是基于java的。 你可以检查DefaultMethodSecurityExpressionHandler的源代码,看看你是否可以重用他们正在做的事情
再晚一点,永远不要,让我把我的2美分价值。
在JSF世界里,在我的托pipebean中,我做了以下操作:
HttpServletRequest req = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest(); SecurityContextHolderAwareRequestWrapper sc = new SecurityContextHolderAwareRequestWrapper(req, "");
如上所述,我的理解是,可以做到这一点:
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); UserDetails userDetails = null; if (principal instanceof UserDetails) { userDetails = (UserDetails) principal; Collection authorities = userDetails.getAuthorities(); }
@gouki答案是最好的!
只是spring真的这样做的一angular。
有一个名为SecurityContextHolderAwareRequestWrapper
的类实现了ServletRequestWrapper
类。
SecurityContextHolderAwareRequestWrapper
覆盖isUserInRole
和search用户Authentication
(由Springpipe理)来查找用户是否有angular色。
SecurityContextHolderAwareRequestWrapper
的代码是这样的:
@Override public boolean isUserInRole(String role) { return isGranted(role); } private boolean isGranted(String role) { Authentication auth = getAuthentication(); if( rolePrefix != null ) { role = rolePrefix + role; } if ((auth == null) || (auth.getPrincipal() == null)) { return false; } Collection<? extends GrantedAuthority> authorities = auth.getAuthorities(); if (authorities == null) { return false; } //This is the loop which do actual search for (GrantedAuthority grantedAuthority : authorities) { if (role.equals(grantedAuthority.getAuthority())) { return true; } } return false; }
这是来自另一端的问题,但我想我会把它扔进去,因为我真的不得不在互联网上挖掘出来。
有很多关于如何检查angular色的内容,但是当你说hasRole(“blah”)
HasRole检查当前authentication的委托人授予的权限
所以当你看到hasRole(“blah”)真的意味着hasAuthority(“blah”) 。
在我看到的情况下,您可以使用一个实现UserDetails的类来完成此操作,该类定义了一个名为getAuthorities的方法。 在这个基本上,你将基本上添加一些new SimpleGrantedAuthority("some name")
到一个基于一些逻辑的列表。 这个列表中的名字是由hasRole语句检查的东西。
我猜在这种情况下,UserDetails对象是当前authentication的主体。 在身份validation提供程序中及其周围发生了一些魔术,更具体地说是发生这种情况的身份validationpipe理器。
在我们的项目中,我们使用的是一个angular色层次结构,而上面的大多数答案只是针对特定angular色的检查,即只检查给定的angular色,而不检查angular色和层次结构。
这个解决scheme:
@Component public class SpringRoleEvaluator { @Resource(name="roleHierarchy") private RoleHierarchy roleHierarchy; public boolean hasRole(String role) { UserDetails dt = AuthenticationUtils.getSessionUserDetails(); for (GrantedAuthority auth: roleHierarchy.getReachableGrantedAuthorities(dt.getAuthorities())) { if (auth.toString().equals("ROLE_"+role)) { return true; } } return false; }
RoleHierarchy在spring-security.xml中定义为一个bean。
你可以从AuthorityUtils类获得一些帮助。 检查angular色作为一个单线:
if (AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities()).contains("ROLE_MANAGER")) { /* ... */ }
注意:这不检查angular色层次结构,如果存在的话。
大多数答案都缺less一些观点:
-
在spring,angular色和权威是不一样的。 在这里看到更多的细节。
-
angular色名称等于
rolePrefix
+authority
。 -
默认的angular色前缀是
ROLE_
,但是它是可configuration的。 看到这里 。
因此,一个合适的angular色检查需要尊重angular色前缀,如果configuration。
不幸的是,Spring中的angular色前缀自定义有点冒失,在很多地方默认的前缀ROLE_
是硬编码的,除此之外,在Spring上下文中检查了一个GrantedAuthorityDefaults
types的bean,如果存在,自定义angular色它的前缀是被尊重的。
将所有这些信息汇总在一起,一个更好的angular色检查器实现将是这样的:
@Component public class RoleChecker { @Autowired(required = false) private GrantedAuthorityDefaults grantedAuthorityDefaults; public boolean hasRole(String role) { String rolePrefix = grantedAuthorityDefaults != null ? grantedAuthorityDefaults.getRolePrefix() : "ROLE_"; return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication()) .map(Authentication::getAuthorities) .map(Collection::stream) .orElse(Stream.empty()) .map(GrantedAuthority::getAuthority) .map(authority -> rolePrefix + authority) .anyMatch(role::equals); } }