Angular 4 can't set CSRF-TOKEN in header

久未见 提交于 2020-01-13 07:20:51

问题


I've got a Spring boot RESTful service with Spring security configured like so:

protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.cors().and()
                /*.formLogin().loginPage("/auth")
                .permitAll().and()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and().httpBasic().and()*/
                .csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and()
                .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
    }

&

public class CsrfHeaderFilter extends OncePerRequestFilter {

private static final String CSRF_COOKIE_NAME = "XSRF-TOKEN";

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
    if (csrf != null) {
        response.addHeader("X-CSRF-TOKEN", csrf.getToken());
        Cookie cookie = WebUtils.getCookie(request, CSRF_COOKIE_NAME);
        String token = csrf.getToken();

        if (cookie == null || token != null && !token.equals(cookie.getValue())) {
            cookie = new Cookie(CSRF_COOKIE_NAME, token);
            cookie.setPath("/");
            response.addCookie(cookie);
        }
    }

    filterChain.doFilter(request, response);
}

}

I'm invoking the RESTful service using Angular 4 (latest version). It's doing a post request an complaining and throwing a 403 Forbidden "Could not verify the provided CSRF token because your session was not found." Which is expected because I when sending the post request the X-CSRF-TOKEN header is not being set but this header does exist:- Set-Cookie:XSRF-TOKEN=; Path=/

Angular:

auth.service.ts:

const body = 'SOMERANDOMKEY1111';

const headers = new HttpHeaders().set('Content-Type', 'application/json').set('withCredentials', 'true');

    return this._http.post(this.endpoint + this.auth, body, {
      headers: headers
    });

app.module.ts (note: using HttpClient for post request):

providers: [ ...
{
    provide: XSRFStrategy, useFactory: xsrfFactory
}...]
export function xsrfFactory() {
  return new CookieXSRFStrategy('XSRF-TOKEN', 'XSRF-TOKEN');
}

I've followed this and read up on the docs but can't seem to get this working.


回答1:


i had same issue when i was started working with Spring and angular5 :

Q: how to set up X-CSRF token on each request made from angular ?

Sol : server side:

  • first you need to configure csrf security on server side

  • on server side you need to write one api which set up cookies on browser (X-CSRF token inside cookies) and this api is hitting without any securities(disable csrf on this api, assume api name /info)

NOTE : /info this api is called only once when angular app first time loaded (you need to add this is in first page which is to be loaded in angular app)

angular side :

  • when application is loaded on first page/component of angular , inside oninit you need to call this route "/info" (you need to create service in angular and call this api there) i set this on my layout/navbar component because when app is loaded this component was first one which loaded

  • then on inside app.module.ts we need to import

import { HttpClientModule } from '@angular/common/http';

and addd this module inside imports array as :

@NgModule({   imports: [
                     HttpClientXsrfModule.withOptions({
                     cookieName: 'XSRF-TOKEN',
                     headerName: 'X-XSRF-TOKEN',
         })]

-then inside services you need to change the request as follows: user.service.ts

 registeruser(data) {
    console.log(data)
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers, withCredentials: true });
    return this.http.post(this.url + '/avssymbuaa/api/register', data, options).map(res => res.json());
  }
  • note : you need to import this on service

import { Http, Headers, RequestOptions, Response, URLSearchParams } from '@angular/http';

may be this one helps you, thanks




回答2:


The response is forbidden because the spring server or your proxy is expect to receive a X-CSRF token in the header and you did not send it.

1.Please make sure that you are doing a POST (on LOG IN) method to receive the CSRF-TOKEN

2.Store the token received in cookies or localstorage

3.Make the post and add token into the header like this:

let headers = new Headers({ 'XSRF-TOKEN', 'the token received after login' });
let options = new RequestOptions({ headers: headers });
return this.http.post(url,body,options);



回答3:


If your Angular UI and RESTful service are in different domains, your Angular code can't read the cookie set by your backend. To resolve that in your local workspace you can set up cli proxy But for production, if you are using Apache HTTP server, you need to set up reverse proxy. Here is an example:

For https

<VirtualHost *:443>
    ServerName localhost
    SSLEngine on
    SSLProxyEngine On
    SSLCertificateFile conf/ssl/newfile.crt
    SSLCertificateKeyFile conf/ssl/newfile.key
    ProxyPass /api/ https://yoursite/api/
    ProxyPassReverse /api/ https://yoursite/api/
</VirtualHost>

For http

<VirtualHost *:80>
    ServerName localhost
    ProxyPass /api/ http://yoursite/api/
    ProxyPassReverse /api/ http://yoursite/api/
</VirtualHost>


来源:https://stackoverflow.com/questions/45765990/angular-4-cant-set-csrf-token-in-header

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!