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

Pio*_*zda 113 java spring-security user-roles

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

@PreAuthorize("hasRole('ROLE_USER')")
Run Code Online (Sandbox Code Playgroud)

如何在Java代码中创建它?就像是 :

if(somethingHere.hasRole("ROLE_MANAGER")) {
   layout.addComponent(new Button("Edit users"));
}
Run Code Online (Sandbox Code Playgroud)

gou*_*uki 136

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

就像是:

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


    if (request.isUserInRole("ROLE_ADMIN")) {
        // code here
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Autowired HttpServletRequest请求; ? (4认同)

Jos*_*seK 70

Spring Security 3.0有这个API

SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)
Run Code Online (Sandbox Code Playgroud)

在使用之前,您必须注入包装器.

SecurityContextHolderAwareRequestWrapper

  • 正如您的答案所述,看起来该方法是静态的,但是您需要一个`SecurityContextHolderAwareRequestWrapper`实例.你可以改进它,解释如何获得它并更多地澄清答案本身. (48认同)
  • 由于人们对如何利用这一点感到困惑。控制器中的代码如下所示。```@RequestMapping(value = "/path/to/controller") public String sampleMethod(SecurityContextHolderAwareRequestWrapper requestWrapper, Model model){ //方法代码 requestWrapper. isUserInRole("角色"); }``` (5认同)
  • 如果这是一个Web应用程序,它看起来不是,你可以添加SecurityContextHolderAwareRequestWrapper作为参数.如果它是一个Web应用程序,您可以将HttpServletRequest声明为参数并调用isUserInRole (4认同)
  • 如何在Controller中检索包装器? (3认同)
  • 如何获取SecurityContextHolderAwareRequestWrapper的实例? (3认同)
  • Xtreme Biker是对的,你怎么得到SecurityContextHolderAwareRequestWrapper类?它不是一个静态对象. (2认同)

Nin*_*nca 62

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

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

  • 这是非常危险的.请注意,切换到GrantedAuthority实现的另一个实现(例如JAAS,通过添加其他授权可能性)将使此代码出现故障.请参阅SimpleGrantedAuthority中的equals()实现 (5认同)
  • 一个更好的答案,但ROLE_ADMIN应该是双引号. (2认同)

小智 46

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

    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;
    }
Run Code Online (Sandbox Code Playgroud)


Gop*_*opi 14

你可以实现如下的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;
  }
Run Code Online (Sandbox Code Playgroud)


小智 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);
}
Run Code Online (Sandbox Code Playgroud)


hol*_*s83 7

您可以从AuthorityUtils类获得一些帮助。检查单线角色:

if (AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities()).contains("ROLE_MANAGER")) {
    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

警告:如果存在角色层次结构,则不会检查角色层次结构。


Utk*_*mir 7

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

  1. 角色和权限在 Spring 中不是一回事。请参阅此处了解更多详情。

  2. 角色名称等于rolePrefix+ authority。

  3. ROLE_但是,默认角色前缀是,它是可配置的。见这里。

因此,如果配置了角色前缀,则正确的角色检查需要尊重角色前缀。

不幸的是,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);
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

在您的服务层中,当您不希望在引用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;
}
Run Code Online (Sandbox Code Playgroud)


Luk*_*ung 5

下面这两个注释是相等的,“hasRole”会自动添加前缀“ROLE_”。确保您有正确的注释。此角色在 UserDetailsS​​ervice#loadUserByUsername 中设置。

@PreAuthorize("hasAuthority('ROLE_user')")
@PreAuthorize("hasRole('user')")
Run Code Online (Sandbox Code Playgroud)

然后,您可以在java代码中获取角色。

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_user"))){
    System.out.println("user role2");
}
Run Code Online (Sandbox Code Playgroud)