Angular的withCredentials未发送cookie

11

我正在使用Angular 8,与旧版后端(ASP.NET MVC 5 Framework)非CORE。 我试图发送网站的cookie,以便来自Angular网站的请求被视为已认证。

我创建了一个拦截器用于此操作。

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

@Injectable()
export class TokenInterceptor implements HttpInterceptor {
  constructor() { }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const newRequest = request.clone({
      withCredentials: true,
    });
    return next.handle(newRequest);
  }

}

这里是请求的代码

private getDefaultConfiguration(): configurationsType {
  return {
    observe: 'response',
    responseType: 'json',
    headers: new HttpHeaders().set('Content-Type', 'application/json')
  };
}

public async get(endpoint: string, params: HttpParams = undefined) {
  const options = this.getDefaultConfiguration();
  if (params !== undefined)
    options.params = params;

  const response: HttpResponse<object> = await this.http.get(endpoint, options).toPromise();
  return await this.errorCheck(response);
}

我可以确认拦截器通过console.log语句正在执行。问题在于,我没有收到请求中的cookies(顺便说一下,是Http Get而不是Post),因此我的请求被视为未经身份验证。

我正在使用以下CORS问题过滤器:

public class AllowCrossSiteAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpResponseBase response = filterContext.RequestContext.HttpContext.Response;

        response.AddHeader("Access-Control-Allow-Origin", "http://localhost:4200");
        response.AddHeader("Access-Control-Allow-Headers", "*");
        response.AddHeader("Access-Control-Allow-Methods", "*");
        response.AddHeader("Access-Control-Allow-Credentials", "true");

        base.OnActionExecuting(filterContext);
    }
}

我全局注册过滤器,

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new AllowCrossSiteAttribute());
    }
}

这是我期望在标头中发送的 cookie,这段代码来自登录方法

var ticket = new FormsAuthenticationTicket(SessionHelper.DefaultSession().KullaniciAdi, model.RememberMe, timeout);
string encrypted = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted)
{
    Expires = DateTime.Now.AddMinutes(timeout),
    HttpOnly = true // cookie not available in javascript.
};

Response.Cookies.Add(cookie);

return RedirectToAction("Index", "Home");

这是Chrome中的Cookie

输入图像描述 如果您需要更多信息,请在评论中询问,我将提供。

更新

  1. 我查看了这篇文章并将 set-cookiesame-site 属性应用于 none,但仍未解决问题。

  2. 我更新了 [AllowCrossSiteAttribute],因为我在Angular中遇到了另一个完全不同的问题。

public class AllowCrossSiteAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpResponseBase response = filterContext.RequestContext.HttpContext.Response;

        response.AddHeader("Access-Control-Allow-Origin", "http://localhost:4200");
        response.AddHeader("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
        response.AddHeader("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
        response.AddHeader("Access-Control-Allow-Credentials", "true");

        base.OnActionExecuting(filterContext);
    }
}

  1. 在每个请求中都被调用的 BaseController 中的 OnAuthorization 方法中,我测试了请求的头信息。
    如果我从旧的 MVC 应用程序中请求某些内容,则可以正确接收到 cookies 进入图像描述
    但是当我从 angular 项目中发出请求时,根本没有接收到任何 Cookies。

进入图像描述

  1. 以下是 Chrome 检查器中 Cookies 的显示方式

    对于 angular 项目 进入图像描述

    以及旧的 MVC 项目 进入图像描述


@Jota.Toledo,我没有这样做,我应该将文章完全应用于我的项目吗?尽管我没有使用Windows授权,但您能否简要描述一下我应该如何针对我的特定情况调整文章。非常感谢您的帮助。 - Hakan Fıstık
我想检查在使用Angular进行登录后,在浏览器中是否未设置cookie的可能性,然后再发出请求。请参阅https://www.blinkingcaret.com/2018/07/18/secure-an-asp-net-core-web-api-using-cookies/,它解释了cookie配置和跨域请求背后的一些核心思想。 - Jota.Toledo
我查看了这篇文章,并将set-cookie的same-site属性设置为none,但仍然无法解决问题。请在您的更新中添加您是如何做到这一点的。 - Jota.Toledo
1
@Jota.Toledo,我不知道该如何感谢你。实际上,在更新了这个问题后,我立即解决了它。将same-site属性设置为none是至关重要的,但这还不够,我还需要添加最后一步才能让魔法发生:从headers: new HttpHeaders().set('Content-Type', 'application/json')中删除.set('Content-Type', 'application/json') - Hakan Fıstık
@HakanFıstık 很高兴听到你的问题已经解决了。只是为了澄清一下;你是通过将HttpCookie#SameSite属性设置为SameSite.None来设置same-site属性的吗?你能确认只是在Angular端移除'Content-Type', 'application/json'头部就解决了问题吗?了解这种情况可能的原因会很有意思。你可以提供一个最小化的MVC应用程序设置,以重现这个问题吗?我很有兴趣详细地研究一下。 - Jota.Toledo
显示剩余16条评论
1个回答

1

这与您的ASP.NET后端无关,而与运行在端口4200上的Angular开发服务器有关,而您的后端服务器正在端口27309上运行。不同的端口使得http://localhost:4200http://localhost:27309成为不同的主机,因此浏览器不会将cookie附加到发送到http://localhost:27309的请求中,尽管Angular的withCredentials:true标志已经设置。

要解决这个问题,请按照this SO答案中所述的方式设置Angular的代理配置(这是Angular中内置的功能)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接