如何检查 Java 代码中的用户权限或权限?例如 - 我想根据角色为用户显示或隐藏按钮。有如下注释:
@PreAuthorize("hasRole('ROLE_USER')")
如何在Java代码中制作它?就像是 :
if(somethingHere.hasRole("ROLE_MANAGER")) {
layout.addComponent(new Button("Edit users"));
}
如何检查 Java 代码中的用户权限或权限?例如 - 我想根据角色为用户显示或隐藏按钮。有如下注释:
@PreAuthorize("hasRole('ROLE_USER')")
如何在Java代码中制作它?就像是 :
if(somethingHere.hasRole("ROLE_MANAGER")) {
layout.addComponent(new Button("Edit users"));
}
您可以使用 HttpServletRequest 对象的 isUserInRole 方法。
就像是:
public String createForm(HttpSession session, HttpServletRequest request, ModelMap modelMap) {
if (request.isUserInRole("ROLE_ADMIN")) {
// code here
}
}
Spring Security 3.0 有这个 API
SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)
在使用之前,您必须注入包装器。
您可以执行以下操作,而不是使用循环从 UserDetails 中查找权限:
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 security 3.0.x 上测试的,不确定其他版本。)
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);
}
您可以从AuthorityUtils类中获得一些帮助。检查角色作为单线:
if (AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities()).contains("ROLE_MANAGER")) {
/* ... */
}
警告:这不会检查角色层次结构(如果存在)。
大多数答案都缺少一些要点:
因此,正确的角色检查需要尊重角色前缀(如果已配置)。
不幸的是,在 Spring 中自定义角色前缀有点 hacky,在许多地方默认前缀ROLE_
是硬编码的,但除此之外,GrantedAuthorityDefaults
在 Spring 上下文中检查类型的 bean,如果存在,自定义角色前缀它有被尊重。
将所有这些信息放在一起,更好的角色检查器实现将类似于:
@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);
}
}
当您在服务层中时,无法使用 JoseK 的答案,您不想从对 HTTP 请求的引用中引入与 Web 层的耦合。如果您正在考虑在服务层解决角色,Gopi 的答案就是要走的路。
但是,它有点长篇大论。可以直接从身份验证访问权限。因此,如果您可以假设您有一个用户登录,则执行以下操作:
/**
* @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;
}
下面这两个注解是相等的,“hasRole”会自动添加前缀“ROLE_”。确保您有正确的注释。此角色在 UserDetailsService#loadUserByUsername 中设置。
@PreAuthorize("hasAuthority('ROLE_user')")
@PreAuthorize("hasRole('user')")
然后,您可以在java代码中获取角色。
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_user"))){
System.out.println("user role2");
}
奇怪的是,我认为这个问题没有标准的解决方案,因为 spring-security 访问控制是基于表达式的,而不是基于 java 的。你可以检查 DefaultMethodSecurityExpressionHandler的源代码,看看你是否可以重用他们在那里做的事情
这有点来自另一端的问题,但我想我会把它扔进去,因为我真的必须在互联网上挖掘才能找到这个问题。
有很多关于如何检查角色的内容,但没有太多说明当你说 hasRole("blah") 时你实际检查的是什么
HasRole 检查当前已验证主体的授予权限
所以当你看到hasRole("blah") 真的意味着 hasAuthority("blah")。
在我所看到的情况下,您使用一个实现 UserDetails 的类来执行此操作,该类定义了一个名为 getAuthorities 的方法。在此,您基本上将new SimpleGrantedAuthority("some name")
根据某些逻辑将一些添加到列表中。此列表中的名称是 hasRole 语句检查的内容。
我猜在这种情况下 UserDetails 对象是当前经过身份验证的主体。在身份验证提供程序内部和周围发生了一些魔法,更具体地说,是使这种情况发生的身份验证管理器。
迟到总比不好,让我投入我的 2 美分。
在 JSF 世界中,在我的托管 bean 中,我执行了以下操作:
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 的答案是最好的!
只是春天如何真正做到这一点的提示。
有一个名为SecurityContextHolderAwareRequestWrapper
实现该类的ServletRequestWrapper
类。
SecurityContextHolderAwareRequestWrapper
覆盖isUserInRole
和搜索用户(由Authentication
Spring 管理)以查找用户是否具有角色。
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;
}
可以使用以下方式检查用户角色:
在 SecurityContextHolder 中使用调用静态方法:
Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.getAuthorities().stream().anyMatch(role -> role.getAuthority().equals("ROLE_NAME"))) { //do something}
使用 HttpServletRequest
@GetMapping("/users")
public String getUsers(HttpServletRequest request) {
if (request.isUserInRole("ROLE_NAME")) {
}
在我们的项目中,我们使用角色层次结构,而上述大多数答案仅针对检查特定角色,即仅检查给定角色,而不检查该角色和层次结构。
解决方案:
@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。
在您的用户模型上,只需添加一个“hasRole”方法,如下所示
public boolean hasRole(String auth) {
for (Role role : roles) {
if (role.getName().equals(auth)) { return true; }
}
return false;
}
我通常使用它来检查经过身份验证的用户是否具有角色 admin 如下
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); // This gets the authentication
User authUser = (User) authentication.getPrincipal(); // This gets the logged in user
authUser.hasRole("ROLE_ADMIN") // This returns true or false
我在 Java8 的帮助下的方法,传递逗号分隔的角色会给你真假
public static Boolean hasAnyPermission(String permissions){
Boolean result = false;
if(permissions != null && !permissions.isEmpty()){
String[] rolesArray = permissions.split(",");
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
for (String role : rolesArray) {
boolean hasUserRole = authentication.getAuthorities().stream().anyMatch(r -> r.getAuthority().equals(role));
if (hasUserRole) {
result = true;
break;
}
}
}
return result;
}
您可以在 Spring Security中使用注解@Secured
或@RolesAllowed
或@PreAuthorise
/ 。@PostAuthorise
请记住:您需要添加此代码
@Configuration
@EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
public class MyConfig extends WebSecurityConfigurerAdapter{
}
在您的配置类前面。您不需要使用所有 3 个参数securedEnabled
, jsr250Enabled
, prePostEnabled
。您只需要一个,具体取决于您要使用的注释。
然后将角色检查注释放在您的控制器类中。
@Secured("ROLE_admin")
@GetMapping("/hello")
public String hello(){
return "hello";
}
或者
@RolesAllowed("ROLE_admin")
@GetMapping("/hello")
public String hello(){
return "hello";
}
或者
@PreAuthorize("hasRole('ROLE_user')")
@GetMapping("/hello")
public String hello(){
return "hello";
}
这是一个教程https://www.baeldung.com/spring-security-method-security