網頁

2019/10/2

Spring Security 取得 CsrfToken

在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>

參考:

沒有留言:

張貼留言