Angular не отправляет Cookie, полученный в Set-Cookie, даже если для withCredentials установлено значение true - PullRequest
0 голосов
/ 28 апреля 2018

Для проверки подлинности на основе файлов cookie мой сервер отправляет Set-Cookie моему приложению Angular. Однако приложение не отправляет значение обратно в дальнейших запросах. Ниже мой код.

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
  withCredentials: true //this is required so that Angular returns the Cookies received from the server. The server sends cookies in Set-Cookie header. Without this, Angular will ignore the Set-Cookie header
};

public getUserProfile(){
    console.log('contacting server at '+this.API_URL +this.GET_USER_PROFILE_URL+"with httpOptions "+httpOptions);
    return this.http.get(this.GET_USER_PROFILE_URL,httpOptions )
      .map(response=>{
        console.log('response from backend service',response);
        let result= <ServerResponse>response; 
        console.log("result is "+result.result+' with additional information '+result.additionalInformation)
        return result;
      })
      .catch(this.handleError);
  }

Сервер отправляет cookie следующим образом в 200OK моего кода (здесь не показан)

Set-Cookie: id=...

Следующее сообщение, однако, не содержит id в cookie, поэтому сервер возвращает 401. Если я вручную добавлю Cookie, используя инструменты отладки браузера, то получу 200OK. Таким образом, я уверен, что проблема заключается в отсутствии значения id в файле cookie.

Что я делаю не так? Нужно ли явно сохранять cookie, полученный в Set-Cookie, и явно добавлять его в дальнейших запросах?

Обновление - В то время, когда SPA изначально загружен, сервер отправляет заголовок Set-Cookie с некоторой другой информацией cookie, связанной с CSRF. Я заметил, что этот файл cookie все еще отправляется приложением. Может быть, Angular соблюдает первый заголовок Set-Cookie, но игнорирует последующие?

Я добавил пару фотографий, чтобы объяснить, что я имею в виду

Во время подписания клиент отправляет cookie, связанный с CSRF. Я не думаю, что это необходимо, так как клиент также отправляет заголовок CSRF, но по какой-то причине это делает. Сервер отвечает Set-Cookie с идентификатором

enter image description here

Затем, когда я запрашиваю профиль, клиент снова отправляет файл cookie CSRF, но не файл cookie id

enter image description here

1 Ответ

0 голосов
/ 02 мая 2018

Наконец-то я смог найти проблему. Путешествие было более приятным, чем результат, поэтому позвольте мне разбить его на шаги, которые я предпринял для решения своей проблемы.

В итоге, это не проблема с Angular. На куки, которую я отправлял, был установлен флаг secureCookie. Когда я тестировал свое приложение без https, похоже, что угловое приложение не использовало (или не получало доступ) заголовок Set-Cookie, полученный в 200 OK.

Мой исходный код для отправки запроса входа на сервер и обработки его ответа был

  return this.http.post(this.SIGNIN_USER_URL,body,httpOptions)
      .map(response=>{
        console.log('response from backend service',response);
        let result= <ServerResponse>response; 
        console.log("result is "+result.result+' with additional information '+result.additionalInformation)
        return result;
      })
      .catch(this.handleError);

Я не использовал опцию observe: 'response', что означало, что ответ будет содержать только тело, а не заголовки. Я изменил код на следующий, чтобы видеть, какие заголовки принимаются.

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' }),

withCredentials: true, 
observe: 'response' as 'response'
};  

public signinUser(user:UserSigninInfo):any{
    console.log('contacting server at '+this.API_URL +this.SIGNIN_USER_URL +" with user data "+user+ " with httpOptions "+httpOptions.withCredentials + ","+httpOptions.headers ); 

    let signinInfo= new UserSignin(user);
    let body = JSON.stringify(signinInfo);
    return this.http.post(this.SIGNIN_USER_URL,body,httpOptions)
      .catch(this.handleError);
  }

Вышеуказанный код вызывался следующим образом. Я изменяю это, чтобы получить заголовки в ответе

return this.bs.signinUser(user).subscribe((res:HttpResponse<any>)=>{console.log('response from server:',res);
  console.log('response headers',res.headers.keys())
} );

Я также создал перехватчик для печати входящих и исходящих сообщений (скопировано из SO)

import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse} from "@angular/common/http";
import {Injectable} from "@angular/core";
import {Observable} from "rxjs/Observable";
import 'rxjs/add/operator/do';

@Injectable()
export class CustomInterceptor implements HttpInterceptor {

  constructor() {
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    console.log("outgoing request",request);
    request = request.clone({
      withCredentials: true
    });
    console.log("new outgoing request",request);

    return next
      .handle(request)
      .do((ev: HttpEvent<any>) => {
        console.log("got an event",ev)
        if (ev instanceof HttpResponse) {
          console.log('event of type response', ev);
        }
      });
  }
}

Когда я начал отладку, я заметил, что хотя сервер отправлял 10 заголовков, только 9 печатались

заголовки с сервера

enter image description here

Распечатать сообщение на консоли (Set-Cookie отсутствует! Заголовок, необходимый моему приложению для получения файла cookie для аутентификации)

0: "Content-Length"
​
1: "Content-Security-Policy"
​
2: "Content-Type"
​
3: "Date"
​
4: "Referrer-Policy"
​
5: "X-Content-Type-Options"
​
6: "X-Frame-Options"
​
7: "X-Permitted-Cross-Domain-Policies"
​
8: "X-XSS-Protection"
​
length: 9

Это дало мне указание, что приложение не видит заголовок Set-Cookie. Я думал, что смогу решить эту проблему, добавив политику CORS в инфраструктуру игры exposedHeaders = ["Set-Cookie"], но это не сработало. Позже я посмотрел поближе на печенье и заметил secureCookie setting

Set-Cookie: id=...Secure; HTTPOnly

Это заставило меня подумать, что, возможно, мои настройки cookie не соответствуют моей среде (localhost, без HTTPS). Я изменил настройки файлов cookie в Silhoutte

val config =  CookieAuthenticatorSettings(secureCookie=false)

И это сработало!

Хотя приведенный выше код работает для secureCookie, и с Angular это не было проблемой, я надеюсь, что некоторые люди сочтут этот подход полезным

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...