Angular 5无法从HttpXsrfTokenExtractor获取XSRF令牌 [英] Angular 5 unable to get XSRF token from HttpXsrfTokenExtractor

查看:133
本文介绍了Angular 5无法从HttpXsrfTokenExtractor获取XSRF令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to make a POST request via an absolute URL to a Spring (Basic authentication) secured Rest API.
Having read that Angular omits inserting the X-XSRF-TOKEN into the request header automatically for absolute urls, I tried to implement an HttpInterceptor to add the token in.

在我的原始/登录 POST请求中,我创建了必要的 authorization:Basic 标头,以确保Spring对请求进行身份验证.
返回的响应标头包含预期的 set-cookie 令牌:

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

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

In my original /signin POST request, I create the necessary authorization: Basic header to ensure Spring authenticates the request.
The response header returned contains the expected set-cookie token:

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

However, in my custom interceptor class when I try to obtain the token from the injected HttpXsrfTokenExtractor for the next request, it returns null.

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

Here is the code for my interceptor class:

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)响应标头返回令牌.


tokenExtractor.getToken() returns null in the above code. I expected it to return the token from Spring (Set-Cookie) response header of my previous /signin request.

我阅读了有关创建拦截器的相关文章:

I read this related post for creating the interceptor:
angular4 httpclient csrf does not send x-xsrf-token

但是除此以外,我找不到更多关于HttpXsrfTokenExtractor的文档:
https://angular.io/api/common/http/HttpXsrfTokenExtractor

问题:为什么 HttpXsrfTokenExtractor.getToken()返回空值?

But I wasn't able to find much documentation for HttpXsrfTokenExtractor other than this:
https://angular.io/api/common/http/HttpXsrfTokenExtractor

Question: Why is HttpXsrfTokenExtractor.getToken() returning null?

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

In addition I added the interceptor class as a provider to the app.module.
Here is my 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 正常工作吗?

我还能错过什么吗?

谢谢您的帮助.


Another thing to note is that I am running my Angular front end on Node.js from localhost:3000 and my Spring Rest back-end from localhost:8080. They are on different ports, and so the reason for making http requests with absolute urls. Would the browser prevent a Set-Cookie working when it comes from a response for a request on a different domain?

Could I be missing anything else?

Thank you for any help.

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

FIX

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

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

----------------------------------------------
[Updated 7th Jan 2018]

FIX

I use Webpack dev server to serve the Angular code. I worked around the issue by configuring a proxy for urls that point to my back-end Rest API.

This means all requests made from the browser now only be to the dev server at port 3000, even for the Rest API calls.
When the webpack dev server sees any request urls with the configured pattern (E.g /api/...), it replaces with calls to the back-end server on http://localhost:8080 (in my case).

This is my what I added to the devServer section of my webpack.dev.js file:

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 .



With this set up, I no longer make cross-domain (cross-origin) requests from the Angular code or use absolute URLs anymore. This hugely simplifies things as I am not fighting the Angular XSRF (CSRF) mechanism anymore. It just works by default. I also do not need to use an HttpInterceptor to manually insert the X-XSRF-TOKEN in either.

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

The added benefit of setting up a dev server proxy is that client requests are no longer absolute, so I do not need to change all the Rest API calls for production.

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

I hope this is useful for anyone who is suffering the same problem/understanding.

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

Webpack dev server proxy documentation ref:
https://webpack.js.org/configuration/dev-server/#devserver-proxy

推荐答案

由于您使用的端口不同(3000和8080),因此您正在发出跨域请求,因此您将无法在其中读取Cookie从服务器发送的客户端.如果要以这种方式分隔客户端和服务器,则需要使用代理,以便从相同的协议(http/https),域和端口为客户端和服务器应用程序提供服务.如果您使用的是Spring Boot,我建议您看一下Spring Cloud Netflix,特别是Zuul(

Since you are using different ports (3000 & 8080), you are making a cross-origin request, so you will not be able to read the cookie in the client sent from the server. If you want to separate your client and server in this way, you need to use a proxy so the client and server applications are served from the same protocol (http/https), domain, and port. If you are using Spring Boot I would suggest you look at Spring Cloud Netflix, specifically Zuul (https://cloud.spring.io/spring-cloud-netflix/single/spring-cloud-netflix.html#_router_and_filter_zuul).

这篇关于Angular 5无法从HttpXsrfTokenExtractor获取XSRF令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆