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

IdentityServer4 Windows认证添加自定义声明失败求助

解决IdentityServer4结合Windows认证时添加自定义用户属性的问题

你的问题核心在于手动修改User身份并重新登录的方式破坏了IdentityServer4的标准认证流程,导致客户端无法完成令牌验证。Windows认证的用户身份需要由IdentityServer通过规范流程处理,自定义声明应该通过IProfileService来注入,而非直接篡改User对象。下面是具体的解决方案:

1. 实现自定义ProfileService补充声明

ProfileService是IdentityServer官方提供的扩展用户声明的入口,我们可以在这里读取Windows认证的用户信息,并添加自定义属性:

using IdentityServer4.Services;
using System.Security.Claims;
using System.Security.Principal;

public class CustomProfileService : IProfileService
{
    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        // 获取当前用户的Windows身份实例
        var windowsIdentity = context.Subject.Identity as WindowsIdentity;
        if (windowsIdentity != null)
        {
            // 添加自定义声明
            var customClaims = new List<Claim>
            {
                new Claim("devhomepage", "www.devsite.com", ClaimValueTypes.String)
            };
            context.IssuedClaims.AddRange(customClaims);
        }

        // 保留原有的Windows认证声明(比如AD用户名、SID等)
        context.IssuedClaims.AddRange(context.Subject.Claims);
    }

    public async Task IsActiveAsync(IsActiveContext context)
    {
        // 简单标记用户为活跃状态,可根据业务需求调整判断逻辑
        context.IsActive = true;
    }
}

2. 注册ProfileService到IdentityServer

在IdentityServer的Startup.cs中,将自定义ProfileService注册到服务容器,同时确保启用Windows认证支持:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryIdentityResources(Config.IdentityResources)
        .AddInMemoryApiScopes(Config.ApiScopes)
        .AddInMemoryClients(Config.Clients)
        .AddProfileService<CustomProfileService>() // 注册自定义ProfileService
        .AddWindowsAuthentication(); // 启用Windows认证中间件
}

3. 配置Identity资源与客户端权限

需要确保自定义声明对应的Identity资源被正确配置,并且客户端有权限访问:

在Config.cs中添加自定义Identity资源

可以单独创建一个包含自定义声明的资源,或者将声明合并到默认的Profile scope中:

public static IEnumerable<IdentityResource> IdentityResources =>
    new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
        // 添加自定义资源,包含我们的devhomepage声明
        new IdentityResource(
            name: "custom_profile",
            displayName: "Custom User Profile",
            userClaims: new[] { "devhomepage" })
    };

更新客户端配置的AllowedScopes

把自定义资源添加到客户端的允许访问列表中:

new Client { 
    ClientId = "mvc", 
    ClientName = "MVC Client", 
    AllowedGrantTypes = GrantTypes.HybridAndClientCredentials, 
    ClientSecrets = { new Secret("secret".Sha256()) }, 
    RedirectUris = {"http://localhost:60640/signin-oidc"},
    PostLogoutRedirectUris = {"http://localhost:60640/signout-callback-oidc"},
    AllowedScopes = new List<string> { 
        IdentityServerConstants.StandardScopes.OpenId, 
        IdentityServerConstants.StandardScopes.Profile,
        "custom_profile" // 加入自定义资源权限
    }, 
    AllowOfflineAccess = true, 
    RequireConsent = false 
}

4. 修正登录逻辑,移除手动SignIn代码

你原来的手动创建ClaimsIdentity并调用HttpContext.SignInAsync(User)的做法是错误的,这会覆盖IdentityServer的原始认证上下文。正确的做法是让IdentityServer自动处理Windows认证后的声明注入,所以登录逻辑应该简化为:

// 移除所有手动添加Identity和SignInAsync的代码,直接跳转到目标页面
return RedirectToLocal(returnUrl);
// 若使用自定义登录页,需确保已通过[Authorize(AuthenticationSchemes = WindowsDefaults.AuthenticationScheme)]触发Windows认证

为什么原来的方案无效?

你手动修改User对象并重新登录,会导致IdentityServer生成的令牌基于你新创建的ClaimsIdentity,而非原始的Windows认证Subject。客户端验证令牌时会发现Subject不匹配,从而触发授权失败。通过ProfileService注入声明是IdentityServer的标准扩展方式,不会破坏原有认证流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:40:54