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

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

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

结果为空;

提前致谢!

【问题讨论】:

    标签: java spring spring-mvc spring-security 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();
             }
          }
          
          1. 启用 csrf 并使用 CookieCsrfTokenRepository csrf 令牌存储库。
          2. 从带有 cookie 名称的 cookie 中获取令牌 - “XSRF-TOKEN”
          3. 在另一个请求中使用此令牌 [GET、HEAD、TRACE、OPTIONS 除外] 标头,标头键为 X-XSRF-TOKEN

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-01-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-10-04
            相关资源
            最近更新 更多