简体   繁体   中英

Spring Security Angular Csrf token

i have configured spring security but still unable to send post request via 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, "/**");
}

my cors configuration source is as follow:

    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;
}

and i am using a root context : api/v1 in the case this might help.

on Angular side i have configured app.module.ts

  imports: [
...
HttpClientModule,
HttpClientXsrfModule,

],

the problem occurs when i try a post request: here is a screenshot of the request and response:

GET Request returns 200 OK:

Get request

Post request returns 403 forbidden:

The bizzare thing is that there are 2 XSRF token which i guess is the source of the problem.

post request

To solve the csrf problem between spring security and angular, you have to do that.

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

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

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

The default angular csrf interceptor does not always work. So you have to implement your own interceptor.

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);
  }
}

And finally add it in your providers (app.module.ts)

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

Think about putting in your imports.

HttpClientXsrfModule.withOptions({
      cookieName: 'XSRF-TOKEN',
      headerName: 'X-CSRF-TOKEN'
}),

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM