You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET8+Umbraco13下按User-Agent配置不同Identity Cookie名称

解决方案:在Umbraco 13/.NET 8中根据User-Agent动态设置Identity Cookie名称

问题根源

  1. Umbraco 13会自行配置ASP.NET Core Identity选项,直接使用ConfigureApplicationCookie可能被Umbraco的配置覆盖,导致自定义事件未触发。
  2. 直接修改context.Options.Cookie.Name会修改全局配置,引发并发请求下的Cookie名称冲突问题。

步骤1:修复自定义事件不触发的问题

首先确保自定义CookieAuthenticationEvents被正确注册并关联到Identity的Application认证方案:

  1. 注册自定义事件类为Scoped服务:
builder.Services.AddScoped<CustomCookieAuthenticationEvents>();
  1. 使用PostConfigure将事件关联到IdentityConstants.ApplicationScheme的Cookie配置:
builder.Services.PostConfigure<CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme, options =>
{
    options.EventsType = typeof(CustomCookieAuthenticationEvents);
});

步骤2:安全动态设置Cookie名称(避免全局冲突)

不要直接修改全局Options.Cookie.Name,而是通过自定义CookieAuthenticationHandler在每个请求的上下文中动态设置Cookie名称,同时确保认证时能正确匹配对应名称的Cookie:

自定义认证Handler

public class DynamicCookieNameAuthenticationHandler : CookieAuthenticationHandler
{
    public DynamicCookieNameAuthenticationHandler(IOptionsMonitor<CookieAuthenticationOptions> options, 
        ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) 
        : base(options, logger, encoder, clock)
    {
    }

    // 认证时根据User-Agent查找对应Cookie
    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var userAgent = Context.Request.Headers["User-Agent"].ToString();
        Options.Cookie.Name = GetCookieName(userAgent);
        return base.HandleAuthenticateAsync();
    }

    // 登录时根据User-Agent设置Cookie名称
    protected override Task HandleSignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
    {
        var userAgent = Context.Request.Headers["User-Agent"].ToString();
        Options.Cookie.Name = GetCookieName(userAgent);
        return base.HandleSignInAsync(user, properties);
    }

    // 根据User-Agent判断Cookie名称的逻辑
    private string GetCookieName(string userAgent)
    {
        return userAgent.Contains("custom-user-agent") 
            ? "MobileAuthCookie" 
            : "DefaultAuthCookie";
    }
}

注册自定义Handler到Umbraco的Identity配置

在Umbraco初始化后,替换IdentityConstants.ApplicationScheme的默认Handler:

builder.Services.AddUmbraco(builder.Environment, builder.Configuration)
    .AddBackOffice()
    .AddWebsite()
    .AddDeliveryApi()
    .AddComposers()
    .Build();

// 替换默认的Cookie认证Handler为自定义实现
builder.Services.PostConfigure<AuthenticationOptions>(options =>
{
    var identityScheme = options.Schemes.FirstOrDefault(s => s.Name == IdentityConstants.ApplicationScheme);
    if (identityScheme != null)
    {
        identityScheme.HandlerType = typeof(DynamicCookieNameAuthenticationHandler);
    }
});

// 注册自定义Handler服务
builder.Services.AddScoped<DynamicCookieNameAuthenticationHandler>();

替代方案:通过ResponseSignIn事件替换Cookie

如果不想自定义Handler,也可以在ResponseSignIn事件中删除默认Cookie,添加自定义名称的Cookie:

public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
{
    public override Task ResponseSignIn(CookieResponseSignInContext context)
    {
        var userAgent = context.HttpContext.Request.Headers["User-Agent"].ToString();
        string targetCookieName = userAgent.Contains("custom-user-agent") 
            ? "MobileAuthCookie" 
            : "DefaultAuthCookie";

        // 获取刚添加的默认Cookie
        var defaultCookie = context.Response.Cookies.FirstOrDefault(c => c.Name == context.Options.Cookie.Name);
        if (defaultCookie != null)
        {
            // 删除默认Cookie
            context.Response.Cookies.Delete(context.Options.Cookie.Name);
            // 添加自定义名称的Cookie,复制原有的选项
            context.Response.Cookies.Append(targetCookieName, defaultCookie.Value, defaultCookie.Options);
        }

        return base.ResponseSignIn(context);
    }

    // 认证时需要根据User-Agent查找对应Cookie
    public override Task ValidatePrincipal(CookieValidatePrincipalContext context)
    {
        var userAgent = context.HttpContext.Request.Headers["User-Agent"].ToString();
        string targetCookieName = userAgent.Contains("custom-user-agent") 
            ? "MobileAuthCookie" 
            : "DefaultAuthCookie";

        // 检查当前请求是否有目标Cookie,没有则标记认证失败
        if (!context.HttpContext.Request.Cookies.ContainsKey(targetCookieName))
        {
            context.RejectPrincipal();
            return context.HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme);
        }

        return base.ValidatePrincipal(context);
    }
}

这种方式需要手动处理认证时的Cookie查找,不如自定义Handler简洁,因此优先推荐自定义Handler的方案。

内容的提问来源于stack exchange,提问作者gtu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 00:50:00