对于基于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);
}
服务器在我的代码200OK中发送cookie如下(此处未显示)
Set-Cookie: id=...
但是下一条消息没有得到cookie中的id
,因此服务器返回401.如果我使用浏览器的调试工具手动添加Cookie,那么我得到200OK。因此,我确信在cookie中没有导致问题的id
值。
我做错了什么?我是否需要明确存储在Set-Cookie
中收到的cookie并明确将其添加到其他请求中?
更新 -
在最初加载SPA时,服务器会发送Set-Cookie
标头以及与CSRF
相关的其他cookie信息。我注意到该cookie仍然由应用程序发送。可能是Angular尊重第一个Set-Cookie
标题而忽略后续标题吗?
我添加了几张照片来解释我的意思
在签名期间,客户端发送与CSRF相关的cookie。我不认为它是必需的,因为客户端也发送CSRF标头但由于某种原因它确实发送。服务器使用带有id的Set-Cookie进行响应
然后,当我要求配置文件时,客户端再次发送CSRF cookie但不发送id cookie
答案 0 :(得分:14)
最后,我找到了问题。旅程比结果更令人满意,所以让我把它分解为我解决问题的步骤。
总之,这不是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);
我没有使用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个正在打印
来自服务器的标头
在控制台上打印消息(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"]
政策来解决此问题,但这不起作用。后来我仔细查看了cookie并注意到secureCookie
设置
Set-Cookie: id=...Secure; HTTPOnly
这让我觉得可能我的cookie设置对我的环境是错误的(localhost,没有HTTPS)。我更改了Silhoutte中的cookie设置
val config = CookieAuthenticatorSettings(secureCookie=false)
它有效!
虽然我会将上面的代码用于secureCookie,这对Angular来说不是问题,但我希望有些人可能会觉得这个方法很有用
答案 1 :(得分:4)
带有标志“ HttpOnly”的“ Set-Cookie”意味着您无法从客户端读取cookie。
答案 2 :(得分:0)
我假设您使用nodejs和express-session来管理会话,然后默认情况下启用了Express-session中的httpOnly,因此您必须为控制台服务器发送的cookie更改httpOnly
const app = require('express')();
var session = require('express-session');
var cookieParser = require('cookie-parser');
下图中的app.use(session( { 秘密:“ hello world”,
商店:SessionStore,
重新保存:false,
Cookie:{
安全:错误,
httpOnly:false //默认情况下为布尔值true }
}));
httpOnly是真实的,因此您无法控制台此cookie。
下图中的httpOnly为false,因此您可以管理此cookie。
答案 3 :(得分:0)
注意 - 如果您在项目中使用 ZUUL,请参考此答案
尝试了所有可能的解决方案(参考文章和n个stackoverflow问题)并敲了2天,终于找到了这个解决方案。感谢 Zuul 文档 - Cookies and Sensitive Headers。
我遇到了同样的问题 - 从 API 响应中,set-Cookie 响应标头即将到来,而当从 Angular 代码调用相同的 api 时,set-cookie 被跳过或忽略。
在 application.yml 或属性文件中的 zuul 配置中使用 'sensativeHeaders' 属性。参考下面的代码片段
zuul:
routes:
users:
path: /myusers/**
sensitiveHeaders:
url: https://downstream
我没有在拦截器中设置任何额外的标题或属性,例如“withCredentials”。
答案 4 :(得分:0)
我们需要在获取 set-cookies 标头时再检查一个选项,
set-cookie: SESSIONID=60B2E91C53B976B444144063; Path=/dev/api/abc; HttpOnly
还要检查 Path 属性值。这应该与您的 API 起始上下文路径相同,如下所示
https://www.example.com/dev/api/abc/v1/users/123
或在不确定上下文路径时使用以下值
Path=/;