使用AngularJS与SpringSecurity3.2的CSRF [英] Using AngularJS with SpringSecurity3.2 for CSRF

查看:1760
本文介绍了使用AngularJS与SpringSecurity3.2的CSRF的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

AngularJS

的index.html

 < HEAD>
    < META NAME =_ CSRFCONTENT =$ {_ csrf.token}/>
    <! - 默认的标题名称为X-CSRF-TOKEN - >
    < META NAME =_ csrf_headerCONTENT =$ {_ csrf.headerName}/>
< /头>

SpringSecurity 3.2

Spring使用的 HttpSessionCsrfTokenRepository 在默认情况下为CSRF给出了头名的 X-CSRF-TOKEN ,但是Anuglar约定的 X-XSRF-TOKEN

我想延长 HttpSessionCsrfTokenRepository 并重写头名,但由于它被标记为最终我最终实现自定义标记库。

  @Component
公共类CustomCsrfTokenRepository实现CsrfTokenRepository {  公共静态最后弦乐CSRF_PARAMETER_NAME =_csrf;  公共静态最后弦乐CSRF_HEADER_NAME =X-XSRF-TOKEN  私人最终地图<弦乐,CsrfToken> tokenRepository =新的ConcurrentHashMap<>();  公共CustomCsrfTokenRepository(){
    log.info(创建{},CustomCsrfTokenRepository.class.getSimpleName());
  }  @覆盖
  公共CsrfToken的generateToken(HttpServletRequest的请求){
    返回新DefaultCsrfToken(CSRF_HEADER_NAME,CSRF_PARAMETER_NAME,createNewToken());
  }  @覆盖
  公共无效saveToken(CsrfToken令牌,HttpServletRequest的请求,HttpServletResponse的响应){
    字符串键= getKey(请求);
    如果(键== NULL)
      返回;    如果(令牌== NULL){
      tokenRepository.remove(键);
    }其他{
      tokenRepository.put(键,令牌);
    }
  }  @覆盖
  公共CsrfToken loadToken(HttpServletRequest的请求){
    字符串键= getKey(请求);
    返回键== NULL?空:tokenRepository.get(键);
  }  私有String getKey(HttpServletRequest的请求){
    返回request.getHeader(授权);
  }  私人字符串createNewToken(){
    返回UUID.randomUUID()的toString()。
  }
}

SecurityConfig.java

  @Configuration
@EnableWebSecurity
公共类SecurityConfig扩展WebSecurityConfigurerAdapter {    @注入
    私人CustomCsrfTokenRepository customCsrfTokenRepository;
     @覆盖
        保护无效配置(HttpSecurity HTTP)抛出异常{            HTTP
    // .addFilterAfter(新CsrfTokenGeneratorFilter(),CsrfFilter.class)
                。异常处理()
                    .authenticationEntryPoint(的AuthenticationEntryPoint)
                    。和()
                .formLogin()
                    .loginProcessingUrl(/应用/验证)
                    .successHandler(ajaxAuthenticationSuccessHandler)
                    .failureHandler(ajaxAuthenticationFailureHandler)
                    .usernameParameter(为j_username)
                    .passwordParameter(为j_password)
                    .permitAll()
                    。和()                 .csrf()
                    .csrfTokenRepository(customCsrfTokenRepository)
                    。和()
              }
           }


  1. 我怎样才能干净地覆盖头名,而不是创建一个自定义csrfTokenRepository的?


  2. 有没有我需要的单页做任何其他配置更改
    应用程序如AngularJS,因为这还没有工作。



解决方案

在使用Java配置Spring Security的,下面应该是可能的:

 公共无效配置(最终HttpSecurity HTTP)抛出异常
  {
    最后HttpSessionCsrfTokenRepository tokenRepository =新HttpSessionCsrfTokenRepository();
    tokenRepository.setHeaderName(X-XSRF-TOKEN);    http.csrf()csrfTokenRepository(tokenRepository)。
  }

并发症是单页面应用程序依靠AJAX和包括CSRF与AJAX请求令牌是一个有点复杂。当使用AngularJS,服务器应在第一次请求,只要发送称为会话cookie XSRF-TOKEN 用户登录或注销。那么AngularJS将返回HTTP头这个cookie的值 X-XSRF-TOKEN 所有的请求,让服务器可以检查。

AngularJS

index.html

<head>
    <meta name="_csrf" content="${_csrf.token}"/>
    <!-- default header name is X-CSRF-TOKEN -->
    <meta name="_csrf_header" content="${_csrf.headerName}"/>
</head>

SpringSecurity 3.2

Spring uses HttpSessionCsrfTokenRepository which by default gives header name for CSRF as X-CSRF-TOKEN, however Anuglar convention is X-XSRF-TOKEN

I wanted to extend HttpSessionCsrfTokenRepository and override the header name, but since it is marked final I ended up implementing a custom token repository.

@Component
public class CustomCsrfTokenRepository implements CsrfTokenRepository {

  public static final String CSRF_PARAMETER_NAME = "_csrf";

  public static final String CSRF_HEADER_NAME = "X-XSRF-TOKEN";

  private final Map<String, CsrfToken> tokenRepository = new ConcurrentHashMap<>();

  public CustomCsrfTokenRepository() {
    log.info("Creating {}", CustomCsrfTokenRepository.class.getSimpleName());
  }

  @Override
  public CsrfToken generateToken(HttpServletRequest request) {
    return new DefaultCsrfToken(CSRF_HEADER_NAME, CSRF_PARAMETER_NAME, createNewToken());
  }

  @Override
  public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
    String key = getKey(request);
    if (key == null)
      return;

    if (token == null) {
      tokenRepository.remove(key);
    } else {
      tokenRepository.put(key, token);
    }
  }

  @Override
  public CsrfToken loadToken(HttpServletRequest request) {
    String key = getKey(request);
    return key == null ? null : tokenRepository.get(key);
  }

  private String getKey(HttpServletRequest request) {
    return request.getHeader("Authorization");
  }

  private String createNewToken() {
    return UUID.randomUUID().toString();
  }
}

SecurityConfig.java

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Inject
    private CustomCsrfTokenRepository customCsrfTokenRepository;


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

            http
    //          .addFilterAfter(new CsrfTokenGeneratorFilter(), CsrfFilter.class)
                .exceptionHandling()
                    .authenticationEntryPoint(authenticationEntryPoint)
                    .and()
                .formLogin()
                    .loginProcessingUrl("/app/authentication")
                    .successHandler(ajaxAuthenticationSuccessHandler)
                    .failureHandler(ajaxAuthenticationFailureHandler)
                    .usernameParameter("j_username")
                    .passwordParameter("j_password")
                    .permitAll()
                    .and()

                 .csrf()
                    .csrfTokenRepository(customCsrfTokenRepository)
                    .and()
              }
           }

  1. How can I cleanly override the header name instead of creating a custom csrfTokenRepository?

  2. Is there any other configuration changes I need to do for Single Page Applications such as AngularJS, as this does not work yet.

解决方案

When using Java configuration for Spring Security, the following should be possible:

  public void configure(final HttpSecurity http) throws Exception
  {
    final HttpSessionCsrfTokenRepository tokenRepository = new HttpSessionCsrfTokenRepository();
    tokenRepository.setHeaderName("X-XSRF-TOKEN");

    http.csrf().csrfTokenRepository(tokenRepository);
  }

The complication is that single-page applications rely on AJAX and including CSRF tokens with AJAX requests is a bit complicated. When using AngularJS, the server should send a session cookie called XSRF-TOKEN upon first request and whenever a user logs in or logs out. AngularJS will then return the value of this cookie in the HTTP header X-XSRF-TOKEN with all requests, which the server can then check.

这篇关于使用AngularJS与SpringSecurity3.2的CSRF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆