問題:
機密情報を含むSpring MVCベースのRESTful APIがあります。 APIは保護する必要がありますが、リクエストごとにユーザーの資格情報(user/passコンボ)を送信することは望ましくありません。 RESTガイドライン(および内部のビジネス要件)に従って、サーバーはステートレスのままにする必要があります。 APIはマッシュアップスタイルのアプローチで別のサーバーによって消費されます。
必要条件:
クライアントは、資格情報を使用して.../authenticate
(保護されていないURL)に要求を出します。サーバーは、将来の要求を検証してステートレスを維持するのに十分な情報を含む安全なトークンをサーバーに返します。これはおそらくSpring Securityのものと同じ情報からなるでしょう Remember-Me Token 。
クライアントは、以前に取得したトークンをクエリパラメータ(またはあまり望ましくないがHTTPリクエストヘッダ)として追加して、さまざまな(保護された)URLに後続のリクエストを行います。
クライアントがクッキーを保存することは期待できません。
私たちはすでにSpringを使っているので、解決策はSpring Securityを利用するべきです。
私たちはこの作品を作ろうとしている壁に頭をぶつけてきたので、うまくいけばそこに誰かがこの問題をすでに解決しています。
上記のシナリオを考えると、この特定のニーズをどのように解決できるでしょうか。
私たちはこれをOPの説明どおりに機能させることができたので、他の人がこのソリューションを利用できることを願っています。これが私たちがしたことです。
セキュリティコンテキストを次のように設定します。
<security:http realm="Protected API" use-expressions="true" auto-config="false" create-session="stateless" entry-point-ref="CustomAuthenticationEntryPoint">
<security:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
<security:intercept-url pattern="/authenticate" access="permitAll"/>
<security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>
<bean id="CustomAuthenticationEntryPoint"
class="com.demo.api.support.spring.CustomAuthenticationEntryPoint" />
<bean id="authenticationTokenProcessingFilter"
class="com.demo.api.support.spring.AuthenticationTokenProcessingFilter" >
<constructor-arg ref="authenticationManager" />
</bean>
ご覧のとおり、カスタムのAuthenticationEntryPoint
を作成しました。これは、要求がフィルターチェーンでAuthenticationTokenProcessingFilter
によって認証されなかった場合に基本的には401 Unauthorized
を返すだけです。
CustomAuthenticationEntryPoint:
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Authentication token was either missing or invalid." );
}
}
AuthenticationTokenProcessingFilter:
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
@Autowired UserService userService;
@Autowired TokenUtils tokenUtils;
AuthenticationManager authManager;
public AuthenticationTokenProcessingFilter(AuthenticationManager authManager) {
this.authManager = authManager;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
@SuppressWarnings("unchecked")
Map<String, String[]> parms = request.getParameterMap();
if(parms.containsKey("token")) {
String token = parms.get("token")[0]; // grab the first "token" parameter
// validate the token
if (tokenUtils.validate(token)) {
// determine the user based on the (already validated) token
UserDetails userDetails = tokenUtils.getUserFromToken(token);
// build an Authentication object with the user's info
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails((HttpServletRequest) request));
// set the authentication into the SecurityContext
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(authentication));
}
}
// continue thru the filter chain
chain.doFilter(request, response);
}
}
明らかに、TokenUtils
はいくつかの秘密の(そして非常に大文字小文字の区別がある)コードを含んでいて、すぐに共有することはできません。そのインターフェースは次のとおりです。
public interface TokenUtils {
String getToken(UserDetails userDetails);
String getToken(UserDetails userDetails, Long expiration);
boolean validate(String token);
UserDetails getUserFromToken(String token);
}
それは良いスタートにあなたを降りるべきです。ハッピーコーディング:)
あなたは ダイジェストアクセス認証 を考えるかもしれません。基本的にプロトコルは以下の通りです。
この通信はすべてヘッダーを介して行われます。これは、jmort253で指摘されているように、urlパラメーターで機密情報を通信するよりも一般的に安全です。
ダイジェストアクセス認証は Spring Security でサポートされています。ドキュメントにはクライアントのプレーンテキストパスワードにアクセスする必要があると記載されていますが、クライアントに対して HA1ハッシュがある場合は正常に認証されます を実行できます。
情報を運ぶトークンに関しては、JSON Web Tokens( http://jwt.io )は素晴らしい技術です。主な概念は、情報要素(クレーム)をトークンに埋め込んでから、トークン全体に署名して、検証側がクレームが本当に信頼できるものであることを検証できるようにすることです。
私はこのJava実装を使います。 https://bitbucket.org/b_c/jose4j/wiki/Home
Springモジュール(spring-security-jwt)もありますが、それが何をサポートしているのかは調べていません。
JSON WebTokensでOAuthを使い始めませんか?
http://projects.spring.io/spring-security-oauth/
OAuth2は標準化された認証プロトコル/フレームワークです。公式OAuth2によると 仕様 :
あなたはより多くの情報を見つけることができます ここ