在spring控制器中获取_csrf

Posted

技术标签:

【中文标题】在spring控制器中获取_csrf【英文标题】:Get _csrf in spring controller 【发布时间】:2016-07-20 06:28:43 【问题描述】:

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

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

结果为空;

提前致谢!

【问题讨论】:

【参考方案1】:

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

最后这对我有用:

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

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

【讨论】:

您基本上是从来自 AJAX 的服务器请求标头中提取令牌。如果要获取headerNamegetParameterNametoken,可以分别使用CsrfToken token = new HttpSessionCsrfTokenRepository().loadToken(request).getHeaderName();CsrfToken token = new HttpSessionCsrfTokenRepository().loadToken(request).getParameterName();CsrfToken token = new HttpSessionCsrfTokenRepository().loadToken(request).getToken();获取。【参考方案2】:

要在 Spring 控制器中访问 CSRF 令牌,您只需执行以下操作:

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

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

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

Documentation

【讨论】:

【参考方案3】:

试试:

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

【讨论】:

感谢@NikolaB 的回复。但它给出了null。在调试中,我看到一个带有键“org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN”的会话属性。 什么是“会话”变量?您如何获得对它的引用? 你应该可以在控制器中注入它(Spring会管理这个):@Autowired private HttpSession session;【参考方案4】:

我认为在您之前的尝试中,您将 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名,第三个是存放在session中的key。 loadToken 方法实际上并没有从请求对象中获取令牌 - 它从请求中获取会话对象,然后查找令牌,该令牌之前使用由 sessionAttributeName 定义的键存储。

【讨论】:

【参考方案5】:

如果您想直接从session 获取它,这也有效

CsrfToken token = (CsrfToken) session.getAttribute("org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN");

【讨论】:

【参考方案6】:

您可以在 Controller 的资源方法中将 HttpServletRequest 实例作为参数。使用此请求对象,您可以轻松获取 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.UUID类创建的Csrf Token值,如下:-

UUID.randomUUID().toString();

检查org.springframework.security.web.csrf.CookieCsrfTokenRepositoryorg.springframework.security.web.csrf.HttpSessionCsrfTokenRepository 类,它们是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();
   

    启用 csrf 并使用 CookieCsrfTokenRepository csrf 令牌存储库。 从带有 cookie 名称的 cookie 中获取令牌 - “XSRF-TOKEN” 在另一个请求中使用此令牌 [GET、HEAD、TRACE、OPTIONS 除外] 标头,标头键为 X-XSRF-TOKEN

【讨论】:

以上是关于在spring控制器中获取_csrf的主要内容,如果未能解决你的问题,请参考以下文章

如何在spring mvc控制器中获取getServletContext()

Laravel 在控制器中手动检查 CSRF

Laravel 4 CSRF 表单通过 Ajax 调用提交

Codeigniter:这种情况下 csrf 不工作

Laravel - 将 VerifyCsrfToken 添加到控制器获取 ajax 请求

Spring security csrf实现前端纯html+ajax