Spring Security를 ​​사용하여 Java 코드에서 "hasRole"을 확인하는 방법은 무엇입니까?


118

Java 코드에서 사용자 권한 또는 권한을 확인하는 방법은 무엇입니까? 예를 들어 역할에 따라 사용자 버튼을 표시하거나 숨기고 싶습니다. 다음과 같은 주석이 있습니다.

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

Java 코드로 만드는 방법은 무엇입니까? 다음과 같은 것 :

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

답변:


70

Spring Security 3.0에는이 API가 있습니다.

SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)

사용하기 전에 래퍼를 주입해야합니다.

SecurityContextHolderAwareRequestWrapper


53
귀하의 답변이 언급했듯이 메서드가 정적 인 것처럼 보이지만 SecurityContextHolderAwareRequestWrapper인스턴스 가 필요 합니다. 그것을 얻는 방법을 설명하고 답 자체를 조금 더 명확하게 설명하면서 그것을 향상시킬 수 있습니다.
— Xtreme Biker

3
컨트롤러에서 래퍼를 어떻게 검색 할 수 있습니까?
— Alfonso Tienda 2015 년

3
SecurityContextHolderAwareRequestWrapper의 인스턴스를 어떻게 얻을 수 있습니까?
— gstackoverflow 2015-09-15

2
Xtreme Biker가 맞습니다. SecurityContextHolderAwareRequestWrapper 클래스를 어떻게 얻습니까? 정적 개체가 아닙니다.
— 시도해보십시오

5
그렇지 않은 것처럼 보이는 웹 앱인 경우 SecurityContextHolderAwareRequestWrapper를 매개 변수로 추가하면됩니다. 이 웹 응용 프로그램 인 경우 그리고 당신은 매개 변수로 HttpServletRequest의를 선언 대해 isUserInRole 부를 수
— 데이비드 브래들리

144

HttpServletRequest 개체의 isUserInRole 메서드를 사용할 수 있습니다.

다음과 같이 :

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


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

내 생각에 테스트하기 더 쉬움
— fego

1
하지만 내가 요청하지 않았다면?
— gstackoverflow

무엇에 대한 ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest()요청을 얻으려면? :)
— Petr Újezdský

4
@Autowired HttpServletRequest 요청; ?
— Pascal

그리고 그것은 Spring API, 평범한 서블릿 사양도 아닙니다! 선택한 답이 아니다 치욕
— gregfqt

67

루프를 사용하여 UserDetails에서 권한을 찾는 대신 다음을 수행 할 수 있습니다.

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

2
훨씬 더 좋은 대답이지만 ROLE_ADMIN은 큰 따옴표로 묶어야합니다.
— Erica Kane

6
이것은 매우 위험합니다. GrantedAuthority 구현의 다른 구현 (예 : 다른 권한 부여 가능성을 추가하여 JAAS)으로 전환하면이 코드가 제대로 작동하지 않습니다. SimpleGrantedAuthority에 등호 () 구현을 참조하십시오
— 페트르 Újezdský

47

보안 컨텍스트를 검색 한 다음 사용할 수 있습니다.

    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()결코 NULL, 문서를 확인하십시오. 따라서 컨텍스트 확인을 피할 수 있습니다 NULL.
— Imtiaz Shakil Siddique

14

다음과 같이 hasRole () 메소드를 구현할 수 있습니다-(이것은 다른 버전에 대해서는 확실하지 않은 스프링 보안 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;
  }

1
SecurityContextHolder.getContext().getAuthentication()검색 할 수 있습니다 null. 수표를 추가할까요?
— Mrusful

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

8

AuthorityUtils 클래스 에서 도움을받을 수 있습니다 . 한 줄로 역할 확인 :

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

주의 사항 : 존재하는 경우 역할 계층을 확인하지 않습니다.


목록을 여러 번 확인하고 마법의 간단한 루틴으로 한 번 가져와야하는 가장 간단한 해결책 입니다!
— LeO

6

JoseK의 답변은 HTTP 요청에 대한 참조에서 웹 계층과의 결합을 도입하고 싶지 않은 서비스 계층에서 사용할 수 없습니다. 서비스 계층에서 역할을 해결하려는 경우 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;
}

6

대부분의 답변에는 몇 가지 요점이 누락되었습니다.

  1. 역할과 권한은 Spring에서 동일하지 않습니다. 자세한 내용은 여기를 참조 하십시오.

  2. 역할 이름은 rolePrefix+ 와 같습니다 authority.

  3. 기본 역할 접두사는 ROLE_이지만 구성 할 수 있습니다. 여기를 참조 하십시오 .

따라서 적절한 역할 검사는 구성된 경우 역할 접두사를 존중해야합니다.

안타깝게도 Spring의 역할 접두사 사용자 정의는 약간 해키입니다. 많은 곳에서 기본 접두사 ROLE_가 하드 코딩되어 있지만 그 외에도 GrantedAuthorityDefaultsSpring 컨텍스트에서 유형의 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);
    }
}

3

이상하게도 스프링 보안 액세스 제어가 자바 기반 이 아닌 표현식 기반 이기 때문에이 문제에 대한 표준 솔루션이 없다고 생각 합니다. DefaultMethodSecurityExpressionHandler 의 소스 코드를 확인하여 그들이하는 일을 재사용 할 수 있는지 확인할 수 있습니다.


따라서 솔루션은 DefaultMethodSecurityExpressionHandler를 빈으로 사용하고 표현식 파서를 가져와 EL에서 확인하는 것입니다.
— Piotr Gwiazda

핸들러가 메서드 호출 (컨텍스트에없는)에서 작동하기 때문에 작동하지 않을 것입니다. 당신은 아마 비슷한 않지만, MethodInvocation의 컨텍스트를 사용하지 않고 자신의 빈 만들 필요
— 숀 패트릭 플로이드를

2

늦게 늦게하는 것이 더 좋을 것입니다. 2 센트 가치를 입력하겠습니다.

JSF 세계에서 관리 빈 내에서 다음을 수행했습니다.


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

2

이것은 다른 쪽 끝에서 질문에 대한 일종의 오는 것이지만 나는 이것을 찾기 위해 인터넷을 파야했기 때문에 그것을 던질 것이라고 생각했습니다.

역할을 확인하는 방법에 대한 내용은 많지만 hasRole ( "blah")라고 말할 때 실제로 확인하는 내용은별로 없습니다.

HasRole은 현재 인증 된 주체에 대해 부여 된 권한을 확인합니다.

따라서 실제로 hasRole ( "blah") 을 볼 때 실제로 hasAuthority ( "blah")를 의미합니다. 합니다.

내가 본 경우에는 getAuthorities라는 메서드를 정의하는 UserDetails를 구현하는 클래스를 사용하여이를 수행합니다. 여기에 기본적으로new SimpleGrantedAuthority("some name") 일부 논리를 기반으로 목록 를 합니다. 이 목록의 이름은 hasRole 문에서 확인한 것입니다.

이 컨텍스트에서 UserDetails 개체는 현재 인증 된 보안 주체라고 생각합니다. 인증 공급자, 특히이를 가능하게하는 인증 관리자 안팎에서 발생하는 마법이 있습니다.


2
Spring Security 4.0에서 이것은 hasRole("bla")이제 hasAuthority("ROLE_bla").
— lanoxx

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

2

아래 두 주석은 동일합니다. "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");
}

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에서 빈으로 정의됩니다.


1
또는 역할을 적절하게 채울 수 있습니다 : github.com/spring-projects/spring-security/issues/…
— arctica

1

사용자 모델에서 아래와 같이 'hasRole'메소드를 추가하십시오.

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

인증 된 사용자에게 다음과 같이 관리자 역할이 있는지 확인하는 데 일반적으로 사용합니다.

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

사용자 역할은 다음과 같은 방법으로 확인할 수 있습니다.

  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")) {
      
    }


0

Java8의 도움으로 내 접근 방식, 쉼표로 구분 된 역할을 전달하면 true 또는 false가 제공됩니다.

    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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.