即使withCredentials为true,Angular也不会发送在Set-Cookie中收到的Cookie

Man*_*dha 17 angular

对于基于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);
  }
Run Code Online (Sandbox Code Playgroud)

服务器在我的代码200OK中发送如下cookie(此处未显示)

Set-Cookie: id=...

然而,下一条消息没有id在cookie中,因此服务器返回401.如果我使用浏览器的调试工具手动添加Cookie,那么我得到200OK.因此,我确信id在cookie中缺少导致问题的价值.

我究竟做错了什么?我是否需要明确存储收到的cookie Set-Cookie并在进一步的请求中明确添加它?

更新 - 在最初加载SPA时,服务器会发送Set-Cookie包含与其相关的其他cookie信息的标头CSRF.我注意到该cookie仍然由应用程序发送.难道Angular会尊重第一个Set-Cookie标题而忽略后续标题吗?

我添加了几张照片来解释我的意思

在签名期间,客户端发送与CSRF相关的cookie.我不认为它是必需的,因为客户端也发送CSRF Header但由于某种原因它确实发送.服务器使用带有id的Set-Cookie进行响应

在此输入图像描述

然后,当我要求配置文件时,客户端再次发送CSRF cookie但不发送id cookie

在此输入图像描述

Man*_*dha 24

最后我找到了这个问题.旅程比结果更令人满意,所以让我把它分解为我解决问题的步骤.

总之,这不是Angular的问题.我发送的cookie上有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);
Run Code Online (Sandbox Code Playgroud)

我没有使用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);
  }
Run Code Online (Sandbox Code Playgroud)

上面的代码被调用如下.我改变它以获得响应中的标题

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

我还创建了一个截取器来打印传入和传出的消息(从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);
        }
      });
  }
}
Run Code Online (Sandbox Code Playgroud)

当我开始调试时,我注意到虽然服务器正在发送10个标题,但只有9个被打印

服务器的标头

在此输入图像描述

在控制台上打印消息(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
Run Code Online (Sandbox Code Playgroud)

这给了我一个方向,应用程序没有看到Set-Cookie标题.我以为我可以通过CORS在播放框架中添加策略来解决它,exposedHeaders = ["Set-Cookie"]但这不起作用.后来我仔细查看了cookie并注意到了secureCookie设置

Set-Cookie: id=...Secure; HTTPOnly
Run Code Online (Sandbox Code Playgroud)

这让我觉得可能我的cookie设置对我的环境是错误的(localhost,没有HTTPS).我更改了Silhoutte中的cookie设置

val config =  CookieAuthenticatorSettings(secureCookie=false)
Run Code Online (Sandbox Code Playgroud)

它奏效了!

虽然我将上面的代码用于secureCookie,这对Angular来说不是问题,但我希望有些人可能会觉得这个方法很有帮助

  • 对于寻找答案的任何人-这是正确的答案。对我来说,很简单,几天后,添加到拦截器中-withCredentials:true (4认同)
  • 如果删除了Secure标志以使其在本地开发中工作,那么它在生产中如何工作? (2认同)

小智 6

带有“HttpOnly”标志的“Set-Cookie”意味着您无法从客户端读取 cookie。