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インスタンスが必要です。あなたはそれを取得する方法を説明し、答え自体をもう少し明確にすることでそれを改善することができます。
エクストリームバイカー、2015

3
コントローラーでラッパーを取得するにはどうすればよいですか?
Alfonso Tienda

3
SecurityContextHolderAwareRequestWrapperのインスタンスを取得するにはどうすればよいですか?
gstackoverflow

2
Xtreme Bikerは正しいです。SecurityContextHolderAwareRequestWrapperクラスはどのように取得しますか?静的オブジェクトではありません。
それを試して

5
これがWebアプリである場合、そうではないように見える場合は、パラメーターとしてSecurityContextHolderAwareRequestWrapperを追加するだけで済みます。そして、それがWebアプリである場合、パラメーターとしてHttpServletRequestを宣言し、isUserInRoleを呼び出すだけです
David Bradley

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ý16年

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は二重引用符で囲む必要があります。
エリカケイン

6
これは非常に危険です。GrantedAuthority実装の別の実装(たとえば、JAAS、別の認証の可能性を追加することによる)に切り替えると、このコードが誤動作することに注意してください。SimpleGrantedAuthorityのequals()の実装を参照してください
PetrÚjezdský16年

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()メソッドを実装できます(これは、他のバージョンについては不明な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;
  }

1
SecurityContextHolder.getContext().getAuthentication()取得できますnull。多分あなたはいくつかのチェックを追加しますか?
Mrusful 2013年

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

警告:ロール階層が存在する場合、これはチェックされません。


これが最も簡単な解決策です。リストを数回確認する必要があり、魔法の単純なルーチンでリストを1回フェッチするのはすばらしいことです。
LeO 2018年

6

JoseKからの回答は、HTTPリクエストへの参照からWebレイヤーとの結合を導入したくないサービスレイヤーでは使用できません。サービス層で役割を解決する方法を検討している場合、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_はハードコーディングされていますが、それに加えて、タイプのBeanGrantedAuthorityDefaults、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);
    }
}

3

不思議なことに、春のセキュリティアクセス制御はJava ベースではなく式ベースであるため、この問題に対する標準的な解決策はないと思います。DefaultMethodSecurityExpressionHandlerのソースコードをチェックして、 そこで行われていることを再利用できるかどうかを確認します。


したがって、解決策は、DefaultMethodSecurityExpressionHandlerをBeanとして使用し、式パーサーを取得してELでチェックすることです。
Piotr Gwiazda 2010年

ハンドラはメソッド呼び出し(コンテキストにはありません)を操作するため、おそらく機能しません。おそらく、同じようなことをするが、メソッド呼び出しコンテキストを使用しない独自のBeanを作成する必要があるでしょう
Sean Patrick Floyd

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

2

これはもう一方の端からの質問に来るようなものですが、私は本当にこれを見つけるためにインターネットを掘る必要があったので、私はそれを投げ入れようと思いました。

役割を確認する方法についてはたくさんありますが、hasRole( "blah")と言ったときに実際に確認していることについてはあまり言いません。

HasRoleは、現在認証されているプリンシパルの付与された権限をチェックします

つまり、実際にhasRole( "blah")を表示した場合、実際にはhasAuthority( "blah")を意味します。

私が見たケースでは、getAuthoritiesと呼ばれるメソッドを定義するImplements 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ユーザーが役割を持っているかどうかを見つけるために、(春によって管理されています)。

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

以下のこの2つの注釈は同じで、「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");
}

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として定義されています。


1
それとも、正しく役割を移入することができます github.com/spring-projects/spring-security/issues/...
アークティカ

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の助けを借りて、昏睡状態で分離された役割を渡すことはあなたに真か偽を与えるでしょう

    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.