主にREST APIをSpringを使用して提供するwebappを作成しようとしています。セキュリティ側を構成しようとしています。
私はこの種のパターンを実装しようとしています: https://developers.google.com/accounts/docs/MobileApps (Googleはそのページを完全に変更したため、もはや意味がありません。ここを参照していました: http://web.archive.org/web/20130822184827/https://developers.google.com/accounts/docs/MobileApps )
ここに私が従う必要があるものがあります:
(たとえば、ユーザーは通常のフォームを使用してログイン/サインアップし、webappはトークンを使用して安全なCookieを提供し、次のAPIリクエストで使用できます)
以下のように通常の認証設定がありました:
@Override protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/mobile/app/sign-up").permitAll()
.antMatchers("/v1/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/loginprocess")
.failureUrl("/?loginFailure=true")
.permitAll();
}
要求内のトークンをチェックしてからセキュリティコンテキストを設定する事前認証フィルターを追加することを考えていました(つまり、通常の後続の認証がスキップされることを意味しますか?)トークンベースのセキュリティであまりやりすぎではありませんが、他のいくつかの例に基づいて、私は次のことを思いつきました:
セキュリティ構成:
@Override protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.addFilter(restAuthenticationFilter())
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint()).and()
.antMatcher("/v1/**")
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/mobile/app/sign-up").permitAll()
.antMatchers("/v1/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/loginprocess")
.failureUrl("/?loginFailure=true")
.permitAll();
}
私のカスタムレストフィルター:
public class RestAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public RestAuthenticationFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
}
private final String HEADER_SECURITY_TOKEN = "X-Token";
private String token = "";
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
this.token = request.getHeader(HEADER_SECURITY_TOKEN);
//If we have already applied this filter - not sure how that would happen? - then just continue chain
if (request.getAttribute(FILTER_APPLIED) != null) {
chain.doFilter(request, response);
return;
}
//Now mark request as completing this filter
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
//Attempt to authenticate
Authentication authResult;
authResult = attemptAuthentication(request, response);
if (authResult == null) {
unsuccessfulAuthentication(request, response, new LockedException("Forbidden"));
} else {
successfulAuthentication(request, response, chain, authResult);
}
}
/**
* Attempt to authenticate request - basically just pass over to another method to authenticate request headers
*/
@Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
AbstractAuthenticationToken userAuthenticationToken = authUserByToken();
if(userAuthenticationToken == null) throw new AuthenticationServiceException(MessageFormat.format("Error | {0}", "Bad Token"));
return userAuthenticationToken;
}
/**
* authenticate the user based on token, mobile app secret & user agent
* @return
*/
private AbstractAuthenticationToken authUserByToken() {
AbstractAuthenticationToken authToken = null;
try {
// TODO - just return null - always fail auth just to test spring setup ok
return null;
} catch (Exception e) {
logger.error("Authenticate user by token error: ", e);
}
return authToken;
}
上記の結果、アプリの起動時に次のエラーが発生します:authenticationManager must be specified
誰もこれを行うための最善の方法を教えてもらえますか-pre_authフィルターがこれを行うための最良の方法ですか?
[〜#〜] edit [〜#〜]
私が見つけたものと、OAuthではなく標準トークン実装を実装するSpring-security(コードを含む)でそれをどのように行ったかを書きました
Spring-securityを使用したソリューションの実装
他の人にも役立つことを願っています。
あなたが言及しているエラーは、使用しているAbstractAuthenticationProcessingFilter
基本クラスがAuthenticationManager
を必要とするからだと思います。使用しない場合は、no-opに設定するか、Filter
を直接実装します。 Filter
がリクエストを認証し、SecurityContext
をセットアップできる場合、通常、ダウンストリーム処理はスキップされます(ダウンストリームフィルターの実装に依存しますが、あなたのアプリなので、おそらくそれらはすべてそのように動作します)。
私なら、APIエンドポイントを完全に別のフィルターチェーン(別のWebSecurityConfigurerAdapter
Bean)に配置することを検討できます。しかし、それは物事を読みやすくするだけで、必ずしも重要ではありません。
(コメントで示唆されているように)車輪を再発明することに気付くかもしれませんが、試してみても害はありません。おそらく、その過程でSpringとSecurityについてさらに学ぶでしょう。
追加: githubアプローチ は非常に興味深い:ユーザーは基本認証でトークンをパスワードとして使用するだけで、サーバーはカスタムフィルターを必要としません(BasicAuthenticationFilter
は問題ありません)。