问题
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