我试图通过绝对URL向
Spring(基本身份验证)安全的Rest API发出POST请求.
读过Angular省略了将X-XSRF-TOKEN自动插入到绝对URL的请求头中之后,我试图实现一个HttpInterceptor来添加令牌.
在我的原始/ signin POST请求中,我创建了必要的授权:Basic头以确保Spring对请求进行身份验证.
返回的响应头包含预期的set-cookie令牌:
设置Cookie:XSRF-TOKEN = 4e4a087b-4184-43de-81b0-e37ef953d755;路径= /
但是,在我的自定义拦截器类中,当我尝试从注入的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);
}
}
tokenExtractor.getToken()在上面的代码中返回null.我希望它从我之前的/ signin请求的Spring(Set-Cookie)响应头返回令牌.
我读了这篇关于创建拦截器的相关文章:angular4 httpclient csrf does not send 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 {}
另外需要注意的是,我在localhost:3000上运行Node.js上的Angular前端,从localhost:8080运行Spring Rest后端.
它们位于不同的端口上,因此使用绝对URL发出http请求的原因.当浏览器来自对不同域上的请求的响应时,它是否会阻止Set-Cookie工作?
我还能错过任何其他东西吗?
感谢您的任何帮助.
———————————————-
[2018年1月7日更新]
固定
我使用Webpack dev服务器来提供Angular代码.我通过为指向我的后端Rest API的url配置代理来解决这个问题.
这意味着从浏览器发出的所有请求现在只能到端口3000的开发服务器,即使对于Rest API调用也是如此.
当webpack开发服务器看到任何具有已配置模式的请求URL(例如,eg / api / …)时,它将替换为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
}
}
通过此设置,我不再从Angular代码发出跨域(跨域)请求或再使用绝对URL.这大大简化了事情,因为我不再与Angular XSRF(CSRF)机制作斗争了.它只是默认工作.我也不需要使用HttpInterceptor手动插入X-XSRF-TOKEN.
设置开发服务器代理的额外好处是客户端请求不再是绝对的,因此我不需要更改所有用于生产的Rest API调用.
我希望这对遇到同样问题/理解的人有用.
Webpack dev服务器代理文档参考:
https://webpack.js.org/configuration/dev-server/#devserver-proxy
最佳答案 由于使用不同的端口(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).