Làm cách nào để kiểm tra hung hasoleole trong mã Java với Spring Security?


118

Làm cách nào để kiểm tra quyền hoặc quyền của người dùng trong Mã Java? Ví dụ: Tôi muốn hiển thị hoặc ẩn nút cho người dùng tùy theo vai trò. Có những chú thích như:

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

Làm thế nào để làm cho nó trong mã Java? Cái gì đó như :

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

Câu trả lời:


70

Spring Security 3.0 có API này

SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)

Bạn sẽ phải tiêm màng bọc, trước khi bạn sử dụng nó.

SecurityContextHolderAwareRequestWrapper


53
Như câu trả lời của bạn đã được nêu, có vẻ như phương thức này là tĩnh, tuy nhiên bạn cần một SecurityContextHolderAwareRequestWrapperthể hiện. Bạn có thể cải thiện nó giải thích làm thế nào để có được nó và làm rõ câu trả lời hơn một chút.
Xtreme Biker

3
Làm cách nào tôi có thể truy xuất trình bao bọc trong Bộ điều khiển?
Alfonso Tienda

3
Làm cách nào tôi có thể lấy phiên bản SecurityContextHolderAwareRequestWrapper?
gstackoverflow

2
Xtreme Biker đã đúng, Làm thế nào để bạn có được lớp SecurityContextHolderAwareRequestWrapper? Nó không phải là một đối tượng tĩnh.
Hãy thử vào

5
Nếu đây là một ứng dụng web, có vẻ như không phải vậy, bạn chỉ cần thêm SecurityContextHolderAwareRequestWrapper làm tham số. Và nếu đó là một ứng dụng web, bạn có thể chỉ cần khai báo httpServletRequest là một tham số và gọi isUserInRole
David Bradley

144

bạn có thể sử dụng phương thức isUserInRole của đối tượng HttpServletRequest.

cái gì đó như:

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


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

Tôi nghĩ dễ kiểm tra hơn
fego 14/214

1
Nhưng nếu tôi không yêu cầu?
gstackoverflow

Điều gì về ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest()nhận được yêu cầu? :)
Petr Újezdský

4
@ Yêu cầu httpServletRequest yêu cầu; ?
Pascal

Và đó thậm chí không phải là API mùa xuân, thông số Servlet đơn giản! Một sự xấu hổ không phải là câu trả lời được chọn
gregfqt

67

Thay vì sử dụng vòng lặp để tìm quyền từ UserDetails, bạn có thể thực hiện:

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

2
Một câu trả lời đẹp hơn nhiều, tuy nhiên ROLE_ADMIN phải ở trong dấu ngoặc kép.
Erica Kane

6
Điều này rất rủi ro. Xin lưu ý rằng việc chuyển sang triển khai thực hiện GrantedAuthority khác (ví dụ: JAAS, bằng cách thêm một khả năng ủy quyền khác) sẽ khiến mã này bị trục trặc. Xem thực hiện bằng () trong SimpleGrantedAuthority
Petr Újezdský

47

Bạn có thể truy xuất bối cảnh bảo mật và sau đó sử dụng:

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

SecurityContextHolder.getContext()là không bao giờ NULL, kiểm tra các tài liệu. Vì vậy, bạn có thể tránh kiểm tra bối cảnh NULL.
Imtiaz Shakil Siddique

14

Bạn có thể triển khai phương thức hasRole () như bên dưới - (Điều này được thử nghiệm trên bảo mật mùa xuân 3.0.x không chắc chắn về các phiên bản khác.)

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

1
SecurityContextHolder.getContext().getAuthentication()có thể lấy null. Có lẽ bạn thêm một số kiểm tra?
Khủng khiếp

10

Tôi đang sử dụng cái này:

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

8

Bạn có thể nhận được một số sự giúp đỡ từ AuthorityUtils lớp. Kiểm tra vai trò như một lớp lót:

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

Hãy cẩn thận: Điều này không kiểm tra phân cấp vai trò, nếu như vậy tồn tại.


Đó là giải pháp đơn giản nhất khiến tôi cần kiểm tra Danh sách nhiều lần và tìm nạp nó một lần với một số thói quen đơn giản kỳ diệu là tuyệt vời!
LeO

6

Câu trả lời từ JoseK không thể được sử dụng khi trong lớp dịch vụ của bạn, nơi bạn không muốn giới thiệu khớp nối với lớp web từ tham chiếu đến yêu cầu HTTP. Nếu bạn đang tìm cách giải quyết các vai trò trong khi ở trong lớp dịch vụ, câu trả lời của Gopi là cách để đi.

Tuy nhiên, nó hơi dài dòng. Các nhà chức trách có thể được truy cập ngay từ Xác thực. Do đó, nếu bạn có thể cho rằng bạn có người dùng đã đăng nhập, thì sau đây:

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

6

Hầu hết các câu trả lời đều thiếu một số điểm:

  1. Vai trò và quyền hạn không giống nhau trong mùa xuân. Xem ở đây để biết thêm chi tiết.

  2. Tên vai trò bằng rolePrefix+ authority.

  3. Tiền tố vai trò mặc định là ROLE_, tuy nhiên, nó có thể cấu hình. Xem ở đây .

Do đó, kiểm tra vai trò thích hợp cần phải tôn trọng tiền tố vai trò nếu nó được cấu hình.

Thật không may, tùy chỉnh tiền tố vai trò trong Spring là một chút hack, ở nhiều nơi, tiền tố mặc định, ROLE_được mã hóa cứng, nhưng ngoài ra, một loại đậuGrantedAuthorityDefaults được kiểm tra trong ngữ cảnh Spring và nếu nó tồn tại, thì tiền tố vai trò tùy chỉnh đã được tôn trọng.

Mang tất cả thông tin này lại với nhau, việc thực hiện kiểm tra vai trò tốt hơn sẽ giống như:

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

3

Thật kỳ lạ, tôi không nghĩ có một giải pháp chuẩn cho vấn đề này, vì điều khiển truy cập bảo mật mùa xuân là dựa trên biểu thức , không dựa trên java. bạn có thể kiểm tra mã nguồn cho DefaultMethodSecurityExpressionHandler để xem liệu bạn có thể sử dụng lại thứ gì đó mà họ đang làm ở đó không


Vì vậy, giải pháp của bạn là sử dụng DefaultMethodSecurityExpressionHandler làm bean và lấy trình phân tích cú pháp biểu thức và kiểm tra nó trong EL?
Piotr Gwiazda

điều đó có thể sẽ không hoạt động, vì trình xử lý hoạt động trên các phương thức (mà bạn không có trong ngữ cảnh của mình). bạn có thể cần phải tạo bean của riêng mình để làm một cái gì đó tương tự, nhưng không sử dụng bối cảnh định vị phương thức
Sean Patrick Floyd

2

Thà muộn còn hơn không bao giờ, hãy để tôi đưa vào trị giá 2 xu của tôi.

Trong thế giới JSF, trong bean được quản lý của tôi, tôi đã làm như sau:


HttpServletRequest req = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
SecurityContextHolderAwareRequestWrapper sc = new SecurityContextHolderAwareRequestWrapper(req, "");

Như đã đề cập ở trên, sự hiểu biết của tôi là nó có thể được thực hiện theo cách dài hơi như sau:


Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDetails userDetails = null;
if (principal instanceof UserDetails) {
    userDetails = (UserDetails) principal;
    Collection  authorities = userDetails.getAuthorities();
}

2

Đây là loại câu hỏi đến từ đầu kia nhưng tôi nghĩ tôi sẽ ném nó vào vì tôi thực sự phải tìm kiếm trên internet để tìm ra điều này.

Có rất nhiều thứ về cách kiểm tra vai trò nhưng không nói nhiều về những gì bạn thực sự kiểm tra khi bạn nói hasRole ("blah")

HasRole kiểm tra các cơ quan có thẩm quyền đối với hiệu trưởng hiện đang được chứng thực

Vì vậy, thực sự khi bạn thấy hasRole ("blah") thực sự có nghĩa là hasAuthority ("blah") .

Trong trường hợp tôi đã thấy, bạn thực hiện điều này với một lớp thực hiện UserDetails xác định một phương thức gọi là getAuthorities. Về cơ bản, bạn sẽ thêm một sốnew SimpleGrantedAuthority("some name") vào danh sách dựa trên một số logic. Các tên trong danh sách này là những thứ được kiểm tra bởi các câu lệnh hasRole.

Tôi đoán trong bối cảnh này, đối tượng UserDetails là hiệu trưởng hiện được xác thực. Có một số phép thuật xảy ra trong và xung quanh các nhà cung cấp xác thực và cụ thể hơn là trình quản lý xác thực thực hiện điều này.


2
Tính đến Spring Security 4.0, điều này hasRole("bla")hiện tương đương với hasAuthority("ROLE_bla").
lanoxx

2

Câu trả lời @gouki là tốt nhất!

Chỉ là một mẹo về cách mùa xuân thực sự làm điều này.

Có một lớp được đặt tên SecurityContextHolderAwareRequestWrappertrong đó thực hiện ServletRequestWrapperlớp.

Việc SecurityContextHolderAwareRequestWrapperghi đè isUserInRolengười dùng và tìm kiếm Authentication(được quản lý bởi Spring) để tìm xem người dùng có vai trò hay không.

SecurityContextHolderAwareRequestWrapper mã là:

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

2

Hai chú thích dưới đây là bằng nhau, "hasRole" sẽ tự động thêm tiền tố "ROLE_". Hãy chắc chắn rằng bạn có chú thích đúng. Vai trò này được đặt trong UserDetailsService # loadUserByUsername.

@PreAuthorize("hasAuthority('ROLE_user')")
@PreAuthorize("hasRole('user')")

Sau đó, bạn có thể nhận được vai trò trong mã java.

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

1

Trong dự án của chúng tôi, chúng tôi đang sử dụng hệ thống phân cấp vai trò, trong khi hầu hết các câu trả lời ở trên chỉ nhằm kiểm tra vai trò cụ thể, tức là chỉ kiểm tra vai trò được đưa ra, chứ không phải cho vai trò đó và lên phân cấp.

Một giải pháp cho việc này:

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

Vai trò phân cấp được định nghĩa là một bean trong spring-security.xml.


1
Hoặc bạn có thể nhập đúng vai trò của mình: github.com/spring-projects/spring-security/issues/ gợi
arctica

1

Trên mô hình người dùng của bạn, chỉ cần thêm phương thức 'hasRole' như bên dưới

public boolean hasRole(String auth) {
    for (Role role : roles) {
        if (role.getName().equals(auth)) { return true; }
    }
    return false;
}

Tôi thường sử dụng nó để kiểm tra xem người dùng được xác thực có quản trị viên vai trò như sau không

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

1

Vai trò người dùng có thể được kiểm tra bằng các cách sau:

  1. Sử dụng các phương thức tĩnh gọi trong SecurityContextHolder:

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

  2. Sử dụng httpServletRequest

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


0

Cách tiếp cận của tôi với sự trợ giúp của Java8, Vượt qua các vai trò được phân tách hôn mê sẽ cho bạn đúng hoặc sai

    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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.