65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET Core Web API / MVC 应用中 Cookie 日志记录中间件

starIconstarIconstarIconstarIconstarIcon

5.00/5 (6投票s)

2021年6月30日

CPOL

3分钟阅读

viewsIcon

10374

关于 Cookie 认证事件

引言

有时,我们需要记录 Cookie 日志,以便在开发站点或生产站点进行调试。我们遇到了类似的情况。

背景

在我们为 Android 客户端提供数据的大型 Web API 中,我们使用了身份验证进行客户端和服务器通信。应用程序的身份验证基于唯一生成的身份验证令牌。每当需要登录时,它都会自动发生。 有一次,我们的客户端提出了一个问题:**一个请求通过了身份验证,但紧随其后的对同一 URI 的下一个请求却失败了**。 我们在任何其他应用程序中都没有遇到过这种情况。 这个错误只发生在 200 多个设备中的一个或两个设备上。

然后我们开始调试会话。首先,我们验证了登录令牌是否有效,它是有效的,然后我们进入了流程的下一步。从任何角度来看,我们在业务方面所做的一切看起来都很好。我们不知道发生了什么。如果这个问题确实存在于 API 端,为什么只有**一个或两个设备出现问题,而不是全部?**

最后,我们开始调试我们收到的 cookie,因为身份验证仅基于 cookie,对吧。如果提交的 cookie 有效,则问题出在 API 端。如果 cookie 不是我们提供给他们的 cookie,那么问题出在应用程序端。为了进行此调试会话,我们开始分析如何记录 cookie。要了解/记录 cookie,我们需要了解以下详细信息

  • 服务器在登录时生成的 Cookie
  • 客户端在每个请求上提交的 Cookie

对于这个大问题,ASP.NET Core 提供了最佳解决方案。我们采用了

  • Cookie 身份验证事件来了解生成的 cookie
  • 中间件来了解提交的 cookie

Cookie 身份验证事件

允许订阅在 cookie 身份验证期间引发的事件。通过订阅 cookie 身份验证事件,我们可以了解 cookie 及其值。主要地,这个 cookie 身份验证事件有以下事件

  • RedirectToAccessDenied
  • RedirectToLogin
  • RedirectToLogout
  • RedirectToReturnURL
  • SigningIn
  • SignedIn
  • SignedOut
  • ValidatePrincipal

我们使用了 RedirectToAccessDenied, SignedIn, SigningIn 事件.

最终,我们的 CookieAuthenticationEvents 类看起来像这样

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using System.Threading.Tasks;

namespace Web
{
    public class MyCookieAuthenticationEvents : CookieAuthenticationEvents
    {
        public override Task RedirectToAccessDenied
               (RedirectContext<CookieAuthenticationOptions> context)
        {
            //Logging the required details
            //Request Body has the client submitted cookie, if submitted 
            //Request available in the context. `context.HttpContext.Request`
            
            return base.RedirectToAccessDenied(context);
        }

        public override Task SigningIn(CookieSigningInContext context)
        {
            //Logging the required details
            
            return base.SigningIn(context);
        }

        public override Task SignedIn(CookieSignedInContext context)
        {            
            //Logging the required details
            //Generated new cookie information available here. In the request Body. 
            //Request available in the HttpContext. `context.HttpContext.Request`
            
            return base.SigningIn(context);
        }
    }
}

我们需要提到这是一个 cookie 身份验证事件侦听器,对吧。这在定义 cookie 身份验证方案的地方完成。在我们的方法中,这是 *startup.cs* 类。此身份验证配置在 *startup.cs* 类的 ConfigureServices 部分下完成。 在 startup 类中的某个地方,我们肯定使用了类似下面的东西

public void ConfigureServices(IServiceCollection services)
{
    ...
    
    services
        .AddAuthentication()
        .AddCookie("<Name Of the Authentication Scheme>", options => 
            { 
                ... 
            });
    ...
}

为了提及 CookieAuthenticationEvents,我们将对上面的代码块进行以下更改

public void ConfigureServices(IServiceCollection services)
{
    ...
    
    services
        .AddAuthentication()
        .AddCookie("", options => 
            { 
                ...
                options.Events = 
                new MyCookieAuthenticationEvents(); // this is newly added line
            });
    ...
}

现在,这将告诉我们生成了哪些 cookie 以及相关详细信息。

Cookie 日志记录中间件

我们分析的第二个重要部分是记录 cookie。为此,我们决定使用中间件。我们的 cookie 日志记录中间件看起来像

using System.Threading.Tasks;

namespace Web
{   
    public class MyCookieLogMiddleware
    {
        private readonly RequestDelegate _next;

        public MyCookieLogMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            await _next.Invoke(context);
            
            //Logging the required details
            //Submitted Cookies available in the request. `context.Request.Cookies`
            //Generated or response cookies available in the response header. 
            // `context.Response.Headers["Set-Cookie"]`
        )                    
	}
}

为了使该中间件工作,我们必须将其添加到应用程序的 ApplicationBuilder 中,也可以通过 *startup.cs* 类实现。此 *Startup.cs* 类具有 Configure 方法。这可以通过具有中间件扩展轻松完成。

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseMyCookieLogMiddleware
                                    (this IApplicationBuilder instance)
    {
        return instance.UseMiddleware<mycookielogmiddleware>();
    }
}

最后,在 *startup.cs* 中

public void Configure(IApplicationBuilder app, 
                      IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    ...
	app.UseAuthentication();
	app.UseCookieLogMiddleware(); //this is the line we have to include.
    ...
    app.UseMvc();
}

此 cookie 日志记录中间件应存在于 UseAuthenticationUseMvc 中间件定义之间。 完成! 现在尝试记录 cookie。

注意事项

身份验证 cookie 是更敏感的信息。如果任何人获取此信息,那么我们将遇到麻烦,因此请注意这一点。不要永久启用它,也不要在第三方可以访问的任何公共场所记录/写入 cookie。

结论

此技巧可能对正在寻找解决方案以记录服务器生成的 cookie 以及客户端应用程序提交的 cookie 的人有所帮助。 感谢您的阅读!

历史

  • 2021年6月30日: 初始版本
© . All rights reserved.