Angular4 httpclient csrf не отправляет x-xsrf-токен

В документации angular указано, что angular httpclient автоматически отправит значение cookie XSRF-TOKEN в заголовке X-XSRF-TOKEN почтового запроса. Ссылка документации

Но он не отправляет мне заголовок. Вот мой код

Код Nodejs для установки файла cookie

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

Я использовал httpclient в app.module.ts

imports: [
  HttpClientModule
]

** Вышеприведенный код предназначен только для целей отладки. У меня нет конечной точки set-csrf.

Но при отправке почтового запроса он не отправляет заголовок. Я не могу отлаживать.

Я добавил проблему в репозиторий github angular тоже. HttpXsrfInterceptor проверяет, является ли запрос GET или HEAD, или если он начинается с http. Если true, он пропускает добавление заголовка.

Вот код в класс 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

Ответ 1

То, что вы ищете, это 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
 }) 
]

Кроме того, если ваш код предназначается для API через абсолютный URL, перехватчик 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 }
]

Ответ 2

Я полагаю, что правильный метод withOptions. Я использовал withConfig и получил ошибку Property 'withConfig' does not exist on type 'typeof HttpClientXsrfModule'. Это проблема с типизацией в документации. Вместо этого вы должны использовать "withOptions" вместо HttpClientXsrfModule.withOptions({ cookieName: 'My-Xsrf-Cookie', headerName: 'My-Xsrf-Header', })

Ответ 3

Используя последнюю версию Angular, я столкнулся со следующей проблемой. Пока токен передается клиенту с использованием имени заголовка "XSRF-TOKEN", ответ должен возвращать токен с использованием имени заголовка "X-XSRF-TOKEN". Итак, вот немного измененная версия кода Мирослава выше, которая работает для меня.

@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);
  }
}