与IdentityServer4会话cookie滑动到期挂钩

问题描述

当IdentityServer对会话cookie(idsrv)执行到期时间的滑动时,我需要运行一些自定义代码(管理另一个自定义cookie)。

如何或在何处挂接到IdentityServer管道来完成此任务? 有可以覆盖的内容还是可以订阅的活动?

我目前正在asp.net core 3.1应用程序中使用IdentityServer4 3.x。

解决方法

AddIdentityServer扩展名只是添加默认的Cookie处理程序。并根据传递的值设置CookieAuthenticationOptions道具。

根据官方描述,滑动有效期如下:

将SlidingExpiration设置为true,以指示处理程序在处理超过到期窗口一半的请求时,每次处理程序以新的到期时间重新发出新的cookie。

考虑到这些,如果您需要对the sliding of the expiration time on the session cookie做某事,则需要有一个自定义Cookie处理程序,其处理方式有所不同

,

这是使用标准的cookie处理程序。

刷新Cookie时,它不会发出任何外部事件,但是有一些方法可以通过副作用检测到这一点。

如果您使用的是自定义ITicketStore,则可以使用StoreAsync来检测何时更改了票证。

如果您不使用自定义票务存储,则可以在附加身份验证中间件之前在 之前附加中间件:

public class CookieSlidingMiddleware
{
    private readonly RequestDelegate next;
    
    public CookieSlidingMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        httpContext.Response.OnStarting(ResponseStarting,httpContext);
        await next(httpContext);
    }

    public async Task ResponseStarting(object contextObject)
    {
        HttpContext httpContext = (HttpContext)contextObject;
        var reponseCookies = httpContext.Response.Cookies;

        if (httpContext.Response.Headers.ContainsKey("Set-Cookie"))
        {
            foreach (var setCookie in httpContext.Response.Headers["Set-Cookie"])
            {
                var cookie = SetCookieHeaderValue.Parse(setCookie);
                if (cookie.Name == "idsrv")
                {
                    if (cookie.Expires == null)
                    {
                        // The cookie is a session cookie,and not sliding
                        return;
                    }
                    else if (cookie.Expires == DateTime.UnixEpoch)
                    {
                        // the cookie is being deleted
                        return;
                    }
                    else if (!httpContext.Request.Cookies.ContainsKey("idsrv"))
                    {
                        // The cookie is being set for the first time
                        return;
                    }
                    else
                    {
                        // the cookie is being refreshed
                        
                        // Do stuff here;
                        return;
                    }
                }
            }
        }
    }
}

cookie身份验证在它自己的Response.OnStarting事件处理程序中处理cookie刷新。

此事件处理程序当前被实现为函数堆栈,因此以相反的顺序调用(即,必须在身份验证中间件之前调用此中间件)。

但是,我认为此呼叫顺序没有任何保证,因此将来可能需要切换该命令。