26

在 Angular 文档中,提到 Angular会自动在post 请求的标头中httpclient发送 cookie 的值。文档链接XSRF-TOKENX-XSRF-TOKEN

但它不会为我发送标题。这是我的代码

设置 cookie 的 Nodejs 代码

router.get('/set-csrf',function(req,res,next){
    res.setHeader('Set-Cookie', "XSRF-TOKEN=abc;Path=/; HttpOnly; SameSite=Strict");    
    res.send();
  })

我在 app.module.ts 中使用了 httpclient

imports: [
  HttpClientModule
]

** 以上代码仅用于调试目的。我没有 set-csrf 端点。

但是当我发送发布请求时它不会发送任何标题。我无法调试。

我也在 Angular 的 github 存储库中添加了这个问题。HttpXsrfInterceptor 检查请求是 GET 还是 HEAD,或者它是否以 http 开头。如果为真,它会跳过添加标题。

这是HttpXsrfInterceptor 类中的代码

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const lcUrl = req.url.toLowerCase();
    // Skip both non-mutating requests and absolute URLs.
    // Non-mutating requests don't require a token, and absolute URLs require special handling
    // anyway as the cookie set
    // on our origin is not the same as the token expected by another origin.
    if (req.method === 'GET' || req.method === 'HEAD' || lcUrl.startsWith('http://') ||
        lcUrl.startsWith('https://')) {
      return next.handle(req);
    }
    const token = this.tokenService.getToken();

    // Be careful not to overwrite an existing header of the same name.
    if (token !== null && !req.headers.has(this.headerName)) {
      req = req.clone({headers: req.headers.set(this.headerName, token)});
    }
    return next.handle(req);
  }

我不确定他们为什么跳过 http/s 部分。这是我在 github 上的问题

4

3 回答 3

61

您正在寻找的是HttpClientXsrfModule.

请在此处阅读更多信息:https ://angular.io/api/common/http/HttpClientXsrfModule 。

你的用法应该是这样的:

imports: [   
 HttpClientModule,  
 HttpClientXsrfModule.withOptions({
   cookieName: 'My-Xsrf-Cookie', // this is optional
   headerName: 'My-Xsrf-Header' // this is optional
 }) 
]

此外,如果您的代码通过绝对 URL 以 API 为目标,则默认的 CSRF 拦截器将无法开箱即用。相反,您必须实现自己的拦截器,它不会忽略绝对路由。

@Injectable()
export class HttpXsrfInterceptor implements HttpInterceptor {

  constructor(private tokenExtractor: HttpXsrfTokenExtractor) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    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);
  }
}

最后将其添加到您的提供商:

providers: [
  { provide: HTTP_INTERCEPTORS, useClass: HttpXsrfInterceptor, multi: true }
]
于 2017-12-01T10:57:26.507 回答
7

我想正确的方法是withOptions。我使用 withConfig 并得到错误Property 'withConfig' does not exist on type 'typeof HttpClientXsrfModule'.这是文档中的输入问题。您需要改用“withOptions”HttpClientXsrfModule.withOptions({ cookieName: 'My-Xsrf-Cookie', headerName: 'My-Xsrf-Header', })

于 2018-03-08T05:39:14.277 回答
0

使用最近的 Angular 版本,我遇到了以下问题。当令牌使用标头名称“XSRF-TOKEN”传递给客户端时,响应必须使用标头名称“X-XSRF-TOKEN”反馈令牌。所以这里是 Miroslav 上面代码的一个稍微修改过的版本,它适用于我。

@Injectable()
export class HttpXSRFInterceptor implements HttpInterceptor {

  constructor(private tokenExtractor: HttpXsrfTokenExtractor) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const headerName = 'XSRF-TOKEN';
    const respHeaderName = 'X-XSRF-TOKEN';
    let token = this.tokenExtractor.getToken() as string;
    if (token !== null && !req.headers.has(headerName)) {
      req = req.clone({ headers: req.headers.set(respHeaderName, token) });
    }
    return next.handle(req);
  }
}
于 2018-05-24T16:24:09.057 回答