Angular 5无法从HttpXsrfTokenExtractor获取XSRF令牌

Gle*_*ung 7 csrf spring-security webpack-dev-server x-xsrf-token angular5

我正在尝试通过绝对URL向Spring(基本身份验证)安全的Rest API 发出POST请求。
阅读了Angular省略了将X-XSRF-TOKEN自动插入到请求标头中以获取绝对URL的信息后,我尝试实现HttpInterceptor来添加令牌。

在我的原始/ signin POST请求中,我创建了必要的授权:基本标头,以确保Spring对请求进行身份验证。
返回的响应标头包含预期的set-cookie令牌:

Set-Cookie:XSRF-TOKEN=4e4a087b-4184-43de-81b0-e37ef953d755; Path=/

但是,在我的自定义拦截器类中,当我尝试从注入的HttpXsrfTokenExtractor中获取下一个请求的令牌时,它返回null

这是我的拦截器类的代码:

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


@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);
   }
}
Run Code Online (Sandbox Code Playgroud)


tokenExtractor.getToken()在以上代码中返回null。我希望它从我先前的/ signin请求的Spring(Set-Cookie)响应标头返回令牌。

我阅读了有关创建拦截器的相关文章:
angular4 httpclient csrf不发送x-xsrf-token

但是除此以外,我找不到更多有关HttpXsrfTokenExtractor的文档:
https

: //angular.io/api/common/http/HttpXsrfTokenExtractor问题:为什么HttpXsrfTokenExtractor.getToken()返回null?

另外,我将拦截器类作为提供程序添加到app.module
这是我的app.module.ts:

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { LocationStrategy, HashLocationStrategy, APP_BASE_HREF } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AlertModule } from 'ng2-bootstrap';
import { routing, appRouterProviders } from './app.routing';
import { HttpXsrfInterceptor } from './httpxrsf.interceptor';
import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './registration/register.component';
import { HomeComponent } from './home/home.component';

@NgModule({
    declarations: [AppComponent,
               LoginComponent,
               RegisterComponent,
               HomeComponent],
    imports: [BrowserModule,
          FormsModule,
          ReactiveFormsModule,
          HttpClientModule,
          HttpClientXsrfModule, // Adds xsrf support
          AlertModule.forRoot(),
          routing],
    schemas: [CUSTOM_ELEMENTS_SCHEMA],
    providers: [
        appRouterProviders,
        [{provide: APP_BASE_HREF, useValue: '/'}],
        [{provide: LocationStrategy, useClass: HashLocationStrategy}],
        [{provide: HTTP_INTERCEPTORS, useClass: HttpXsrfInterceptor, multi: true }]
    ],
    bootstrap: [AppComponent]
})
export class AppModule {}
Run Code Online (Sandbox Code Playgroud)


要注意的另一件事是,我从localhost:3000在Node.js上运行我的Angular前端,从localhost:8080在 Spring Rest后端上运行。它们在不同的端口上,因此使用绝对url发出http请求的原因。当来自另一个域的请求响应时,浏览器会阻止Set-Cookie正常工作吗?

我还能错过什么吗?

感谢您的任何帮助。

----------------------------------------------
[1月7日更新[2018]

FIX

我使用Webpack开发服务器来服务Angular代码。我通过为指向我的后端Rest API的URL 配置代理来解决此问题。

这意味着从浏览器发出的所有请求现在仅发送到端口3000的开发服务器,即使对于Rest API调用也是如此。
webpack开发服务器看到具有配置模式(例如/ api / ...)的任何请求url时,它将替换为对http:// localhost:8080上的后端服务器的调用(在我的情况下)。

这是我在webpack.dev.js的devServer部分添加的内容 文件:

proxy: {
    '/api': {
    'target': 'http://localhost:8080',
    'pathRewrite': {'^/api' : ''}
    //Omits /api from the actual request. E.g. http://localhost:8080/api/adduser -> http://localhost:8080/adduser
    }
}
Run Code Online (Sandbox Code Playgroud)



通过此设置,我不再从Angular代码发出跨域(跨域)请求,也不再使用绝对URL。由于我不再使用Angular XSRF(CSRF)机制,因此极大地简化了事情。它仅在默认情况下有效。我也不需要使用HttpInterceptor来手动在其中插入X-XSRF-TOKEN

设置开发服务器代理的另一个好处是客户端请求不再是绝对的,因此我不需要为生产而更改所有的Rest API调用。

我希望这对于遭受相同问题/理解的任何人都是有用的。

Webpack开发服务器代理文档参考:https ://webpack.js.org/configuration/dev-server/#devserver-proxy

dsp*_*ies 4

由于您使用不同的端口(3000 和 8080),您正在发出跨源请求,因此您将无法读取从服务器发送的客户端中的 cookie。如果您想以这种方式分离客户端和服务器,则需要使用代理,以便客户端和服务器应用程序通过相同的协议 (http/https)、域和端口提供服务。如果您使用 Spring Boot,我建议您查看 Spring Cloud Netflix,特别是 Zuul ( https://cloud.spring.io/spring-cloud-netflix/single/spring-cloud-netflix.html#_router_and_filter_zuul )。