对于基于 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(此处未显示)
设置 Cookie:id=...
然而,下一条消息在 cookie 中没有得到 id
,因此服务器返回 401。如果我使用浏览器的调试工具手动添加 Cookie,那么我得到 200OK。因此,我确定是导致问题的 cookie 中缺少 id
值。
我做错了什么?我是否需要显式存储在 Set-Cookie
中收到的 cookie 并在进一步的请求中显式添加它?
更新 -
在 SPA 初始加载时,服务器发送 Set-Cookie
header 以及一些与 CSRF
相关的其他 cookie 信息。我注意到该 cookie 仍由应用程序发送。会不会是 Angular 尊重第一个 Set-Cookie
header 但忽略后续 header ?
我添加了几张图片来解释我的意思
在签名过程中,客户端发送一个与CSRF相关的cookie。我不认为这是必需的,因为客户端也发送 CSRF header ,但出于某种原因它确实如此。服务器响应带有 id 的 Set-Cookie
然后当我请求配置文件时,客户端再次发送 CSRF cookie 而不是 id cookie
最佳答案
终于,我找到了问题所在。旅程比结果更令人满意,所以让我将其分解为解决问题的步骤。
总而言之,这不是 Angular 的问题。我发送的 cookie 上有 secureCookie
标记。当我在没有 https
的情况下测试我的应用程序时,似乎 Angular 应用程序没有使用(或访问)200 OK 中收到的
。Set-Cookie
header
我将登录请求发送到服务器并处理其响应的初始代码是
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'
选项,这意味着响应将只包含正文,而不包含标题。我将代码更改为以下内容,以便我可以看到正在接收哪些 header 。
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);
}
上面的代码被调用如下。我更改它以获取响应中的 header
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 个 header ,但只有 9 个被打印
来自服务器的 header
在控制台上打印消息(Set-Cookie
丢失!我的应用程序需要获取身份验证 cookie 的 header )
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
header 。我以为我可以通过在播放框架 exposedHeaders = ["Set-Cookie"]
中添加 CORS
策略来解决它,但这没有用。后来我仔细观察了 cookie 并注意到 secureCookie
设置
Set-Cookie: id=...Secure; HTTPOnly
这让我觉得我的 cookie 设置可能不适合我的环境(本地主机,没有 HTTPS)。我更改了 Silhoutte 中的 cookie 设置
val config = CookieAuthenticatorSettings(secureCookie=false)
成功了!
虽然我会让上面的代码适用于 secureCookie 而这不是 Angular 的问题,但我希望某些人可能会发现这种方法有帮助
关于即使 withCredentials 为真,Angular 也不会发送在 Set-Cookie 中收到的 Cookie,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50076352/