即使withCredentials为true,Angular也不会发送在Set-Cookie中收到的Cookie [英] Angular is not sending the Cookie received in Set-Cookie even if withCredentials is true

查看:170
本文介绍了即使withCredentials为true,Angular也不会发送在Set-Cookie中收到的Cookie的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于基于cookie的身份验证,我的服务器将Set-Cookie发送到我的Angular应用程序.但是,应用程序不会在进一步的请求中将值发送回.以下是我的代码.

For cookie based authentication, my server sends Set-Cookie to my Angular application. However, the application doesn't send the value back in further requests. Following is my code.

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

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

The server sends the cookie as follows in 200OK of my code (not shown here)

Set-Cookie: id=...

但是下一条消息在cookie中没有id,因此服务器返回401.如果我使用浏览器的调试工具手动添加cookie,则得到200OK.因此,我确定是cookie中缺少id值的原因.

The next message however hasn't got the id in the cookie, thus the server returns 401. If I manually add the Cookie using browser's debug tools, then I get 200OK. Thus I am certain it is the absence of the id value in the cookie which is causing the issue.

我做错了什么?我是否需要显式存储在Set-Cookie中接收的cookie,并在其他请求中显式添加它?

What am I doing wrong? Do I need to explicitly store the cookie received in Set-Cookie and explicitly add it in further requests?

更新- 在最初加载SPA时,服务器发送Set-Cookie标头以及与CSRF有关的其他cookie信息.我注意到该cookie仍由应用程序发送.可能是Angular兑现了第一个Set-Cookie标头,却忽略了随后的标头吗?

Update - At the time when the SPA is initially loaded, the server sends Set-Cookie header with some other cookie's information related to CSRF. I notice that that cookie is still sent by the application. Could it be that Angular honors the first Set-Cookie header but ignores the subsequent ones?

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

I have added couple of pics to explain what I mean

在签名期间,客户端发送与CSRF相关的cookie.我认为这不是必需的,因为客户端也发送CSRF标头,但出于某种原因,它确实需要发送CSRF标头.服务器以其中包含ID的Set-Cookie进行响应

During signing, the client sends a cookie related to CSRF. I dont think it is required as the client also sends CSRF Header but for some reason it does. The server responds with Set-Cookie with id in it

然后,当我请求个人资料时,客户端再次发送CSRF cookie,但不发送id cookie

Then when I ask for profile, the client again sends the CSRF cookie but not the id cookie

推荐答案

最后,我找到了问题所在.旅程比结果更令人满意,所以让我将其分解为解决问题所采取的步骤.

Finally I was able to find the issue. The journey was more satisfying than the result so let me break it down into the steps I took to solve my problem.

总而言之,这与Angular无关.我发送的cookie上有secureCookie标志.当我在没有https的情况下测试我的应用程序时,似乎有角度的应用程序没有使用(或访问)200 OK中收到的Set-Cookie标头.

In summary, This wansn't an issue with Angular. The cookie I was sending had secureCookie flag on. As I was testing my application without https, it seems that the angular application was not using (or getting access to) the Set-Cookie header received in 200 OK.

我将登录请求发送到服务器并处理其响应的初始代码是

My initial code to send the sign in request to the server and handling its response was

  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'选项,这意味着响应将仅包含正文,而不包含标头.我将代码更改为以下代码,以便可以看到正在接收的标头.

I wasn't using observe: 'response' option which meant that the response would only contain body, not headers. I changed the code to following so that I could see which headers are being received.

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

上面的代码被调用如下.我将其更改为在响应中获取标题

The above code was being called as follows. I change that to get the headers in the response

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

我还创建了一个拦截器来打印传入和传出的消息(从SO复制)

I also created an intercepter to print the incoming and outgoing messages (copied from 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个被打印

When I started debugging, I noticed that though the server was sending 10 headers, only 9 were getting printed

服务器标头

在控制台上打印消息(缺少Set-Cookie!我的应用程序获取身份验证cookie所需的标头)

Print message on console (Set-Cookie was missing! The header my application needed to get authentication 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标头.我以为我可以通过在播放框架exposedHeaders = ["Set-Cookie"]中添加CORS策略来解决该问题,但这没有用.后来我仔细查看了cookie,发现secureCookie设置

This gave me a direction that the application is not seeing Set-Cookie header. I thought I'll be able to resolve it by adding CORS policy in play framework exposedHeaders = ["Set-Cookie"] but that didnt work. Later I looked closer at the cookie and noticed secureCookie setting

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

这使我认为我的cookie设置可能不适合我的环境(本地主机,没有HTTPS).我在Silhoutte中更改了cookie设置

This made me think that maybe my cookie settings are wrong for my environment (localhost, no HTTPS). I changed the cookie settings in Silhoutte

val config =  CookieAuthenticatorSettings(secureCookie=false)

它奏效了!

尽管我将使上面的代码适用于secureCookie,而Angular并不是这个问题,但我希望有些人会发现该方法有用

Though I'll make the above code work for secureCookie and this wasn't an issue with Angular, I hope that some folks might find the approach helpful

这篇关于即使withCredentials为true,Angular也不会发送在Set-Cookie中收到的Cookie的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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