Spring Security Angular Csrf令牌

时间:2019-03-16 17:50:23

标签: angular spring-security csrf csrf-protection csrf-token

我已经配置了spring安全性,但仍然无法通过angular发送帖子请求:

  @Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .authenticationProvider(credentialsAuthenticationProvider)
            .httpBasic()
            .and()
            .logout()
            .and()
            .cors().configurationSource(corsConfigurationSource)
            .and()
            .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}

/* To allow Pre-flight [OPTIONS] request from browser */
@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}

我的cors配置源如下:

    public CorsConfigurationSource corsConfigurationSource() {
    final CorsConfiguration configuration = new CorsConfiguration();
    List<String> allowedOrigins = new LinkedList<>();
    allowedOrigins.add("*");
    List<String> allowedHeaders = new LinkedList<>();
    allowedHeaders.add("*");
    List<String> allowedMethods = new LinkedList<>();
    allowedMethods.add("HEAD");
    allowedMethods.add("GET");
    allowedMethods.add("POST");
    allowedMethods.add("PUT");
    allowedMethods.add("DELETE");
    allowedMethods.add("PATCH");
    allowedMethods.add("OPTIONS");
    configuration.setAllowedOrigins(allowedOrigins);
    configuration.setAllowedMethods(allowedMethods);
    configuration.setAllowCredentials(true);
    configuration.setAllowedHeaders(allowedHeaders);
    allowedHeaders.add("Authorization");
    allowedHeaders.add("Content-Type");
    allowedHeaders.add("x-xsrf-token");
    allowedHeaders.add("xsrf-token");
    allowedHeaders.add("Accept-language");
    allowedHeaders.add("X-Requested-With");
    configuration.setAllowedHeaders(allowedHeaders);
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

并且我正在使用根上下文:api / v1,可能会有所帮助。

在Angular端,我已配置app.module.ts

  imports: [
...
HttpClientModule,
HttpClientXsrfModule,

],

当我尝试发布请求时出现问题:这是请求和响应的屏幕截图:

GET请求返回200 OK:

Get request

发布请求返回禁止的403:

奇怪的是,有2个XSRF令牌,我想这是问题的根源。

post request

1 个答案:

答案 0 :(得分:0)

要解决弹簧安全性和角度之间的csrf问题,您必须这样做。

-lt替换为

.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());

默认的角度csrf拦截器并不总是有效。因此,您必须实现自己的拦截器。

        csrf()
        .ignoringAntMatchers ("/login","/logout")
        .csrfTokenRepository (this.getCsrfTokenRepository());

}
private CsrfTokenRepository getCsrfTokenRepository() {
        CookieCsrfTokenRepository tokenRepository = 
        CookieCsrfTokenRepository.withHttpOnlyFalse();
        tokenRepository.setCookiePath("/");
        return tokenRepository;
}

最后将其添加到您的提供程序(app.module.ts)

import {Injectable, Inject} from '@angular/core';
import {HttpInterceptor, HttpXsrfTokenExtractor, HttpRequest, HttpHandler,
  HttpEvent} from '@angular/common/http';
import {Observable} from "rxjs";


@Injectable()
export class HttpXsrfInterceptor implements HttpInterceptor {

  constructor(private tokenExtractor: HttpXsrfTokenExtractor) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    let requestMethod: string = req.method;
    requestMethod = requestMethod.toLowerCase();

    if (requestMethod && (requestMethod === 'post' || requestMethod === 'delete' || requestMethod === 'put')) {
      const headerName = 'X-XSRF-TOKEN';
      let token = this.tokenExtractor.getToken() as string;
      if (token !== null && !req.headers.has(headerName)) {
        req = req.clone({headers: req.headers.set(headerName, token)});
      }
    }

    return next.handle(req);
  }
}

考虑放入您的进口商品。

providers: [{ provide: HTTP_INTERCEPTORS, useClass: HttpXsrfInterceptor, multi: true }]