2

私はSpring MVC Webサイトで作業しており、LDAP経由のActive Directoryで認証を追加しています。会社は Web サイトのアクセス許可をマップするために AD 機関を使用したくありません。各ユーザーのアクセス許可をリストするデータベースがあるため、それに接続してアクセス許可を取得し、ユーザーの認証トークンに追加しようとしています。

私が最初に始めたとき、私はADユーザーグループの権限をaでマッピングしてGrantedAuthoritiesMapperいましたが、それが機能していました。次のように見えました。

public class ActiveDirectoryGrantedAuthoritiesMapper implements GrantedAuthoritiesMapper {

    private static final String ROLE_ADMIN = "adminUserGroup";

    public ActiveDirectoryGrantedAuthoritiesMapper()
    { }

    public Collection<? extends GrantedAuthority> mapAuthorities(
            final Collection<? extends GrantedAuthority> authorities)
    {

        Set<CustomAuthority> roles = EnumSet.noneOf(CustomAuthority.class);

        for (GrantedAuthority authority : authorities)
        {
            if (ROLE_ADMIN.equals(authority.getAuthority()))
            {
                roles.add(CustomAuthority.ROLE_ADMIN);
            }
            //Default role for all users.
            roles.add(CustomAuthority.ROLE_EMPLOYEE);
        }
        return roles;
    }
}

今、私はそれを変換して、データベースにアクセス許可を照会しようとしています。これを行うためにから離れたのGrantedAuthoritiesMapperには 2 つの理由があります。まず、LDAP の機関を使用していないのに、なぜ傍受するのですか? また、内部でログインしているユーザーの名前を取得する方法がわかりませんでしたGrantedAuthoritiesMapper。を使用してみSecurityContextましたが、NullPointerException電話をかけようとcontext.getAuthentication().getName()すると、ユーザーがまだ完全に認証されていないためと思われます。

そこで、 を使用するように切り替えましたAuthenticationSuccessHandler。ロジックをほぼ同じに保とうとしました。ユーザーの認証トークンにロールを追加しようとしていますが、拡張されていないauthentication.getAuthorities().add(...);というエラーが発生します。拡張はしませんが、インターフェースを実装します。これは列挙型だったのではないかと思っていたので、クラスに変更しましたが、まだエラーが発生しています。私が今持っているカスタムのコードは次のとおりです。CustomAuthorityGrantedAuthorityAuthenticationSuccessHandler

public class CustomAuthoritiesMapper implements AuthenticationSuccessHandler 
{
    private CustomPermissionDAO permissionsDao = new CustomPermissionDAO();

    private static final String ROLE_ADMIN = "ADMIN_ACCOUNT";

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException
    {
        List<GrantedAuthority> roles = new ArrayList<GrantedAuthority>();

        List<DatabasePermission> permissionsForUser = permissionsDao.getPermissionByUsername(authentication.getName());

        for (DatabasePermission permission : permissionsForUser)
        {
            if (ROLE_ADMIN.equals( permission.getTag() ))
            {
                roles.add(new CustomAuthority("ROLE_ADMIN"));
            }
            //Default role for all users.
            roles.add(new DashboardAuthority("ROLE_EMPLOYEE"));
        }
        for(GrantedAuthority auth : roles)
        {
            authentication.getAuthorities().add(auth);
        }
    }
}

考えられるすべての組み合わせを試してみました.. List<GrantedAuthority>CustomAuthority オブジェクトのリストに変更しました。個々のものを追加する代わりに使用してみましaddAll(roles)た..この同じエラーのバリエーションが発生するたびに:

Collection 型のメソッド add(capture#1-of ? extends GrantedAuthority) は、引数 (GrantedAuthority) には適用されません。

そして CustomAuthority コード:

public class CustomAuthority implements GrantedAuthority
{
    private String name;

    public CustomAuthority(String name)
    {
        this.name = name;
    }

    public String getAuthority() {
        return name;
    }
}

どんな助けでも大歓迎です。

「関連する質問」を見ると、ここでは authentication.getName() が機能しないように見えますが、その問題に取り組む前に、ユーザーの権限に追加したい権限を追加できない理由を理解したいと思います。

4

2 に答える 2

2

元の質問に対する回答ではありません。これは、これを別の方法でどのように行うことができるかについての命題です。

私にとって変わっているのは、 とによってAuthenticationSuccessHandler行われるはずのものに使用することです。LDAP 用と DB 用の2 つの を想像してください。問題は、デフォルトでそれらを組み合わせると、最初のプロバイダーのみが使用されることです。少し異なるロジックでカスタムを準備できます。AuthenticationManagerAuthenticationProvidersAuthenticationProvidersAuthenticationManagerAuthenticationManager

  • 2 つのプロバイダーについて知っている
  • 正しい順序でそれらを呼び出します
  • 2 つのプロバイダーからの 2 つの認証結果を 1 つのグローバルな結果に結合し、LDAP からユーザー資格情報を取得し、DB から権限を取得します。

欠点: 3 番目の認証プロバイダーを追加しようとしている新しい開発者は、カスタムに驚くかもしれませんAuthenticationManager

利点: コードは適切な場所に適していると思います。

お役に立てれば。

于 2013-07-15T08:50:37.597 に答える
1

SecurityContext から現在のユーザー名を取得できない理由は、まだ入力されていないためです (どのロールを含めるかをまだ検討中です)。

1 つのオプションは、FAQ で説明されているようにLdapAuthenticationProvider と aa LdapAuthoritiesPopulator を使用することです。これはよくある質問の例です

public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator {
    @Autowired
    JdbcTemplate template;

    public List<GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) {
        List<GrantedAuthority> = template.query("select role from roles where username = ?",
                                                   new String[] {username},
                                                   new RowMapper<GrantedAuthority>() {
            /**
             *  We're assuming here that you're using the standard convention of using the role
             *  prefix "ROLE_" to mark attributes which are supported by Spring Security's RoleVoter.
             */
            public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException {
                return new GrantedAuthorityImpl("ROLE_" + rs.getString(1));
            }
        });
    }
}

ユーザー名が渡されるため、これはうまくいくはずです。そのユーザー名をクエリに使用して、ユーザーのロールを取得します。

FAQ に記載されているように、カスタム LdapAuthoritiesPopulator を使用して LdapAuthenticationProvider に接続する必要があります。

もう 1 つのオプションは、カスタム UserDetailsContextMapper を挿入することです。デフォルトは LdapUserDetailsMapper で、ロジックの実装方法がわかります。

于 2013-07-12T22:05:30.490 に答える