如何使用Spring Security检查Java代码中的“hasRole”?

时间:2010-06-11 08:12:40

标签: java spring-security user-roles

如何检查Java代码中的用户权限或权限?例如 - 我想根据角色为用户显示或隐藏按钮。有一些注释:

@PreAuthorize("hasRole('ROLE_USER')")

如何在Java代码中创建它?类似的东西:

if(somethingHere.hasRole("ROLE_MANAGER")) {
   layout.addComponent(new Button("Edit users"));
}

18 个答案:

答案 0 :(得分:131)

您可以使用HttpServletRequest对象的isUserInRole方法。

类似的东西:

public String createForm(HttpSession session, HttpServletRequest request,  ModelMap   modelMap) {


    if (request.isUserInRole("ROLE_ADMIN")) {
        // code here
    }
}

答案 1 :(得分:68)

Spring Security 3.0具有此API

SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)

在使用它之前,你必须注入包装器。

SecurityContextHolderAwareRequestWrapper

答案 2 :(得分:61)

您可以执行以下操作,而不是使用循环从UserDetails中查找权限:

Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
boolean authorized = authorities.contains(new SimpleGrantedAuthority("ROLE_ADMIN"));

答案 3 :(得分:44)

您可以检索安全上下文,然后使用:

    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;
    }

答案 4 :(得分:13)

你可以实现如下的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;
  }

答案 5 :(得分:10)

我正在使用它:

@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);
}

答案 6 :(得分:6)

您可以从AuthorityUtils课程获得一些帮助。检查角色是一行的:

if (AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities()).contains("ROLE_MANAGER")) {
    /* ... */
}

警告:这不会检查角色层次结构(如果存在)。

答案 7 :(得分:5)

在您的服务层中,当您不希望在引用HTTP请求时引入与Web层的耦合时,不能使用JoseK的答案。如果您正在考虑在服务层中解决角色,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;
}

答案 8 :(得分:4)

大多数答案都缺少一些观点:

  1. 角色和权限在Spring中不是一回事。请参阅此处了解more详细信息。

  2. 角色名称等于rolePrefix + authority

  3. 默认角色前缀为ROLE_,但是,它是可配置的。请参阅here

  4. 因此,正确的角色检查需要尊重角色前缀(如果已配置)。

    不幸的是,Spring中的角色前缀自定义有点hacky,在许多地方默认前缀ROLE_是硬编码的,但除此之外,还检查了GrantedAuthorityDefaults类型的bean。 Spring上下文,如果存在,则尊重它所拥有的自定义角色前缀。

    将所有这些信息整合在一起,更好的角色检查器实现将是:

    @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);
        }
    }
    

答案 9 :(得分:2)

晚了好,从来没有,让我投入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();
}

答案 10 :(得分:2)

奇怪的是,我不认为这个问题有一个标准的解决方案,因为spring-security访问控制是expression based,而不是基于java的。你可以查看源代码 DefaultMethodSecurityExpressionHandler看看你是否可以重复使用他们正在做的事情

答案 11 :(得分:2)

@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;
    }

答案 12 :(得分:1)

可以使用以下方式检查用户角色:

  1. 在SecurityContextHolder中使用调用静态方法:

    Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.getAuthorities().stream().anyMatch(role -> role.getAuthority().equals("ROLE_NAME"))) { //do something}

  2. 使用HttpServletRequest

@GetMapping("/users")
public String getUsers(HttpServletRequest request) {
    if (request.isUserInRole("ROLE_NAME")) {
      
    }

答案 13 :(得分:1)

在我们的项目中,我们使用角色层次结构,而上述大多数答案仅针对检查特定角色,即仅检查给定的角色,而不是检查该角色和层次结构。

解决方案:

@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。

答案 14 :(得分:1)

这有点来自另一端的问题,但我想我会把它丢进去,因为我真的不得不在网上挖掘才能找到它。

关于如何检查角色有很多内容,但是当你说hasRole(&#34; blah&#34;)

时,没有太多说明你实际检查的内容

HasRole会检查当前已验证的主体的授权权限

所以当你看到 hasRole(&#34; blah&#34;)时真的意味着hasAuthority(&#34; blah&#34;)

在我看过的情况下,你使用一个实现UserDetails的类来实现这一点,该类定义了一个名为getAuthorities的方法。在此,您基本上会根据某些逻辑将一些new SimpleGrantedAuthority("some name")添加到列表中。此列表中的名称是hasRole语句检查的内容。

我想在这个上下文中,UserDetails对象是当前经过身份验证的主体。在身份验证提供程序中及其周围发生了一些神奇的事情,更具体地说,身份验证管理器可以实现这一点。

答案 15 :(得分:0)

借助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;
}

答案 16 :(得分:0)

下面的这两个注释相等,“ hasRole”将自动添加前缀“ ROLE_”。确保您具有正确的注释。该角色在UserDetailsS​​ervice#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");
}

答案 17 :(得分:0)

在您的用户模型上,只需添加如下的“ 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