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.