在Spring Security取得目前的CsrfToken物件的方法如下。
CsrfToken物件可透過HttpServletRequest物件的attribute以名稱"_csrf"取得。
Spring Security產生的CsrfToken預設是在HttpSessionCsrfTokenRepository.generateToken()產生的DefaultCsrfToken物件,預設的request attribute參數名稱定義在HttpSessionCsrfTokenRepository內的DEFAULT_CSRF_PARAMETER_NAME = "_csrf";,此外也會以CsrfToken.class.getName()取得的名稱"CsrfToken"存放在request attributes。
上述過程請見CsrfFilter.doFilterInternal()。
所以可以從HttpServletRequest物件以下面兩種方式取得。
CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
或從HttpSession取得。
CsrfToken token = (CsrfToken) session.getAttribute("HttpSessionCsrfTokenRepository.CSRF_TOKEN");
例如在Spring Security驗證成功後,在自訂的驗證成功處理器DemoAuthenticationSuccessHandler中由HttpServletRequest取得CsrfToken,然後將token值放入response送出。
DemoAuthenticationSuccessHandler
package com.abc.demo.config;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.csrf.CsrfToken;
import com.fasterxml.jackson.databind.ObjectMapper;
public class DemoAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf"); // get CsrfToken
Map<String, String> data = Collections.singletonMap("csrf_token", csrfToken.getToken());
ObjectMapper objectMapper = new ObjectMapper();
response.getOutputStream().println(objectMapper.writeValueAsString(data));
}
}
回傳的response body的結果。
{"csrf_token":"f172c4e9-bc97-4eca-9fbc-1df9c4c70268"}
如果CsrfToken總是null,那可能Spring Security的csrf停用了,也就是把HttpSecurity.csrf().disable()。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable(); // <-- 無法取得CsrfToken。
}
在傳統的xml設定則是如下。
<http>
...
<csrf disabled="true"/>
</http>
參考:
沒有留言:
張貼留言