最近、Spring Security3.2を使用するプロジェクトにCSRF保護を導入しました。
CSRFを有効にした後、csrfトークンがリクエストに存在しないため、一部の単体テストが失敗します。 '_csrf'パラメーターにダミー値を入れましたが、機能しませんでした。
とにかく、リクエストを送信する前にcsrfトークンを取得できますか(ユニットテスト時)?
あなたの答えuiroshanはcsrfトークンの目的を打ち破っています:あなたの構成ではそれは定数値になります(あなたの構成があなたのテストコンテキストでのみ使用され、あなたがそれを指定しなかった場合を除きます)。
この問題を解決する正しい(そしてより簡単な)方法は次のとおりです。
_import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
...
@Test
public void testLogin() throws Exception {
this.mockMvc.perform(post("/login")
.param("username", "...")
.param("password", "...")
.with(csrf()))
.andExpect(status().isFound())
.andExpect(header().string("Location", "redirect-url-on-success-login"));
}
_
重要な部分は次のとおりです。.with(csrf())
は、予想される__csrf
_パラメーターをクエリに追加します。
csrf()
staticメソッドは_spring-security-test
_によって提供されます:
_<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>5.1.8.RELEASE / 5.2.2.RELEASE</version>
<scope>test</scope>
</dependency>
_
ユニットテストにアクセスするには、次のインポートが必要です。
_ import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
_
カスタムCsrfTokenRepository実装を作成することにより、この問題を修正するための回避策を見つけました。これにより、常に定数トークン( "test_csrf_token"など)が生成されます。したがって、そのトークンを他のフォームパラメータとともにリクエストパラメータとして送信できます(変更されないため)。問題を解決するために実行した手順は次のとおりです。
csrfTokenRepositoryインターフェースを実装するクラスを作成します。一定のトークン値を持つトークンの生成を実装します。
public CsrfToken generateToken(HttpServletRequest request) {
return new DefaultCsrfToken(headerName, parameterName, "test_csrf_token");
}
@Override
public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
if (token == null) {
HttpSession session = request.getSession(false);
if (session != null) {
session.removeAttribute(sessionAttributeName);
}
} else {
HttpSession session = request.getSession();
session.setAttribute(sessionAttributeName, token);
}
}
@Override
public CsrfToken loadToken(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session == null) {
return null;
}
return (CsrfToken) session.getAttribute(sessionAttributeName);
}
セキュリティ構成にcsrfタグへの参照を追加します。
<http>
<csrf token-repository-ref="customCsrfTokenRepository" />
....
</http>
<beans:bean id="customCsrfTokenRepository" class="com.portal.controller.security.TestCsrfTokenRepository"></beans:bean>
Csrfリクエストパラメーターを追加して、テストケースを変更します。
request.addParameter("_csrf", "test_csrf_token");
@Thierryの回答に加えて、リアクティブスタックにも同様のソリューションがあります。
バックエンドをWebTestClient
で呼び出す場合:
import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.csrf
// ...
webTestClient.mutateWith(csrf()).post()...