web-dev-qa-db-ja.com

リクエストパラメータに基づくSpringセキュリティ認証

私が取り組んでいるアプリケーションには、フォームベース認証を処理するためのSpringSecurityがすでに備わっています。ここでの要件は、外部サービスを介してプログラムでユーザーにログインすることですifトークンが要求パラメーターの1つに見つかりました。

つまり、「トークン」などの特定のリクエストパラメータが存在する場合、そのトークンを使用して外部サービスを呼び出し、それが有効なトークンかどうかを確認する必要があります。その場合、ユーザーはログインします。

ログインフォームがないため、Spring Securityを「トリガー」または「フックオン」してこのパラメーターをチェックし、検証を行ってから、必要に応じてユーザーを認証する方法と場所がわかりません。これを行うために拡張またはカスタマイズできる何かがSpring Securityにあるはずだと思いましたか?

Spring Securityのドキュメントを調べて、AbstractPreAuthenticatedProcessingFilterが最初から正しいものかどうかを知りました

16
Bing Qiao

アプリケーションにも同様の設定があります。私が知る限り、これは基本的な要素です:

次のようにAuthenticationProviderを作成する必要があります。

public class TokenAuthenticationProvider implements AuthenticationProvider {

    @Autowired private SomeService userSvc;

    @Override
    public Authentication authenticate(Authentication auth) throws AuthenticationException {
        if (auth.isAuthenticated())
            return auth;

        String token = auth.getCredentials().toString();
        User user = userSvc.validateApiAuthenticationToken(token);
        if (user != null) {
            auth = new PreAuthenticatedAuthenticationToken(user, token);
            auth.setAuthenticated(true);
            logger.debug("Token authentication. Token: " + token + "; user: " + user.getDisplayName());
        } else
            throw new BadCredentialsException("Invalid token " + token);
        return auth;
    }
}

また、カスタムパラメータを認証トークンに変換するには、Filterを作成する必要があります。

public class AuthenticationTokenFilter implements Filter {


    @Override
    public void init(FilterConfig fc) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException {
        SecurityContext context = SecurityContextHolder.getContext();
        if (context.getAuthentication() != null && context.getAuthentication().isAuthenticated()) {
            // do nothing
        } else {
            Map<String,String[]> params = req.getParameterMap();
            if (!params.isEmpty() && params.containsKey("auth_token")) {
                String token = params.get("auth_token")[0];
                if (token != null) {
                    Authentication auth = new TokenAuthentication(token);
                    SecurityContextHolder.getContext().setAuthentication(auth);
                }
            }
        }

        fc.doFilter(req, res);
    }

    @Override
    public void destroy() {

    }

    class TokenAuthentication implements Authentication {
        private String token;
        private TokenAuthentication(String token) {
            this.token = token;
        }
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return new ArrayList<GrantedAuthority>(0);
        }
        @Override
        public Object getCredentials() {
            return token;
        }
        @Override
        public Object getDetails() {
            return null;
        }
        @Override
        public Object getPrincipal() {
            return null;
        }
        @Override
        public boolean isAuthenticated() {
            return false;
        }
        @Override
        public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        }
        @Override
        public String getName() {
            // your custom logic here
        }
    }

 }

これらのBeanを作成する必要があります。

<beans:bean id="authTokenFilter" class="com.example.security.AuthenticationTokenFilter" scope="singleton" />
<beans:bean id="tokenAuthProvider" class="com.example.security.TokenAuthenticationProvider" />

最後に、これらのBeanをセキュリティ構成にワイヤリングする必要があります(それに応じて調整します)。

<sec:http >
   <!-- other configs here -->
   <sec:custom-filter ref="authTokenFilter" after="BASIC_AUTH_FILTER" /> <!-- or other appropriate filter -->
</sec:http>

<sec:authentication-manager>
    <!-- other configs here -->
    <sec:authentication-provider ref="tokenAuthProvider" />
</sec:authentication-manager>

別の方法があるかもしれませんが、これは間違いなく機能します(現時点ではSpring Security 3.1を使用しています)。

22
Dan

ターゲット要求パラメーターが渡されるSpringMVCコントローラーまたはサービスを使用する場合は、@ PreAuthorizeSpringセキュリティアノテーションを使用できます。

たとえば、渡されたトークンをチェックして、渡されたトークンが有効な場合に認証を実行できるSpringサービスがあるとします。

@Service("authenticator")
class Authenticator {        
...
public boolean checkTokenAndAuthenticate(Object token) {
    ...
    //check token and if it is invalid return "false"
    ...
    //if token is valid then perform programmatically authentication and return "true"  
}
...             
}    

次に、Spring security @PreAuthorizeアノテーションを使用すると、次の方法でこれを行うことができます。

...
@PreAuthorize("@authenticator.checkTokenAndAuthenticate(#token)")
public Object methodToBeChecked(Object token) { ... }
...

また、Springセキュリティアノテーションを有効にし、Spring-security-aspectsをPOM(またはjarからクラスパス)に追加する必要があります。

4
nndru