在 spring 控制器中获取 _csrf

Get _csrf in spring controller

如何在 spring 控制器中获取 _csrf 对象 (?!)?我已经配置了 Spring 安全并且可以在 jsp 文件中获取 ${_csrf} 请求属性。 我试过:

CsrfToken _csrf = (CsrfToken) session.getAttribute("CsrfToken");
CsrfToken _csrf = (CsrfToken) session.getAttribute("_csrf");

结果为空;

提前致谢!

尝试:

CsrfToken token = (CsrfToken) session.getAttribute(CsrfToken.class.getName());

在调试中,我看到一个带有键 "org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN" 的会话属性。我查看了 HttpSessionCsrfTokenRepository class。它有一个从传入的 HttpServletRequest 对象加载令牌的方法。

最后这对我有用:

CsrfToken token = new HttpSessionCsrfTokenRepository().loadToken(request);

如果有人向我解释这是如何工作的,我将不胜感激。

我认为在您之前的尝试中,您混淆了 CSRF 参数名称和会话属性名称,并且还尝试了 CsrfToken.class.getName(),这可能在早期版本中使用过,也可能没有使用过。很简单,您的想法是正确的,但密钥是错误的。 如果您查看 HttpSessionCsrfTokenRepository 的源代码,您会看到它定义了以下默认值:

private String parameterName = DEFAULT_CSRF_PARAMETER_NAME;
private String headerName = DEFAULT_CSRF_HEADER_NAME;
private String sessionAttributeName = DEFAULT_CSRF_TOKEN_ATTR_NAME;

第一个是token作为POST参数出现时的参数名,第二个是请求头中出现时的header名,第三个是存放它的key在会话中。 loadToken 方法实际上并没有从请求对象中获取令牌 - 它从请求中获取会话对象,然后查找令牌,该令牌先前使用 sessionAttributeName 定义的密钥存储。

如果您想直接从 session

获取它,这也适用
CsrfToken token = (CsrfToken) session.getAttribute("org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN");

要在 Spring 控制器中访问 CSRF 令牌,您只需这样做:

@Controller
public class FooController {
    @RequestMapping("/foo")
    public void foo(CsrfToken token) {
        // Do whatever with token
    }
}

Spring 将根据参数类型自动检测到您需要的令牌,并将其注入到您的方法中。

这至少从 Spring Security 5.0 起有效,如果您使用 Spring 引导或在您的配置中有 @EnableWebSecurity 注释。

Documentation

您可以在 Controller 的资源方法中将 HttpServletRequest 实例作为参数。使用此请求 object 您可以轻松获得 csrf 令牌。

@Controller
@RequestMapping("/api/v1/test")
public class TestController {
   
  @GetMapping
  public String test(HttpServletRequest request) {
    CsrfToken csrfToken = 
           (CsrfToken)httpServletRequest.getAttribute(CsrfToken.class.getName());
    if(csrfToken != null)
      return csrfToken.getToken();
    return "Token Not Found";
  }

}

使用java.util.UUIDclass创建的Csrf Token值,如下:-

UUID.randomUUID().toString();

检查 org.springframework.security.web.csrf.CookieCsrfTokenRepositoryorg.springframework.security.web.csrf.HttpSessionCsrfTokenRepository classes,它们是 CsrfTokenRepository 的实现,在 spring-security-web-X.X.X.RELEASE.jar.

如果你想在 cookie 中包含 CSRF 令牌并在客户端(比如浏览器)进行响应,那么:-

    @Configuration
@EnableWebSecurity
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {

   @Override
   protected void configure(HttpSecurity http) throws Exception {

   http
     .csrf()
     .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
     .and()
     .....
     .forLogin();
   }
}
  1. 启用 csrf 并使用 CookieCsrfTokenRepository csrf 令牌存储库。
  2. 使用 cookie 名称从 cookie 中获取令牌 -“XSRF-TOKEN”
  3. 在其他请求中使用此令牌 [GET、HEAD、TRACE、OPTIONS 除外] header 以 header 键作为 X-XSRF-TOKEN