C# IdentityServer4自定义身份验证处理程序可以';找不到用户的所有声明

C# IdentityServer4自定义身份验证处理程序可以';找不到用户的所有声明,c#,asp.net-identity,identityserver4,claims-based-identity,C#,Asp.net Identity,Identityserver4,Claims Based Identity,我使用的是使用Asp.Net Identity和EntityFramework的IdentityServer4示例 我正在尝试使用基于声明/角色的自定义策略创建组控件 我的问题是,当我尝试在授权处理程序中获取用户声明时,我要查找的声明不会返回 查看SSMS中的数据库,我发现我创建的声明/角色位于名为“AspNetRoles”、“AspNetRoleClaims”、“AspNetUserClaims”的表中,我创建的用户位于“AspNetUsers”中,用户和角色的密钥位于“AspNetUserR

我使用的是使用Asp.Net Identity和EntityFramework的IdentityServer4示例

我正在尝试使用基于声明/角色的自定义策略创建组控件

我的问题是,当我尝试在授权处理程序中获取用户声明时,我要查找的声明不会返回

查看SSMS中的数据库,我发现我创建的声明/角色位于名为“AspNetRoles”、“AspNetRoleClaims”、“AspNetUserClaims”的表中,我创建的用户位于“AspNetUsers”中,用户和角色的密钥位于“AspNetUserRoles”中。 当我调用获取用户授权声明时,声明列表似乎来自“IdentityClaims”表

在“AspNetClaims”中检查索赔似乎没有像在“IdentityClaims”中检查索赔那样简单的方法,因此我假设我在某个地方犯了错误

我已经四处寻找了一个解决方案,尝试了一些方法,但我找不到任何有效的方法

下面是我认为与问题最相关的代码,以及一些运行代码的截图

任何帮助都将不胜感激,提前谢谢


代码 MvcClient.Startup

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

    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

    services.AddAuthorization(options =>
    {
        options.AddPolicy("AdminRights", policy =>
        {                 
            policy.Requirements.Add(new AdminRequirement());
            policy.RequireAuthenticatedUser();
            policy.AddAuthenticationSchemes("Cookies");
        });
    });

    services.AddSingleton<IAuthorizationHandler, AdminRequirementHandler>();

    services.AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie("Cookies")
        .AddOpenIdConnect("oidc", options =>
        {
            options.SignInScheme = "Cookies";

            options.Authority = "http://localhost:5000";
            options.RequireHttpsMetadata = false;

            options.ClientId = "mvc";
            options.ClientSecret = "secret";
            options.ResponseType = "code id_token token"; // NEW CHANGE (token)

            options.SaveTokens = true;
            options.GetClaimsFromUserInfoEndpoint = true;

            options.Scope.Add("api1");
            options.Scope.Add("AdminPermission"); // NEW CHANGE
            options.Scope.Add("offline_access");
        });
}
IdentityServerWithAspIdAndEF.Startup(在配置中最后调用)


图像

--编辑--

我已经修改了你的代码,解决了这个问题

这是我的回购协议的链接

为了修复您的解决方案,我还更改了服务器身份验证响应类型:-

"code Id_token"
在config.cs中的MVC客户端设置中,我添加了以下属性:-

 AlwaysSendClientClaims = true, 
 AlwaysIncludeUserClaimsInIdToken = true 
我还从mvc客户端删除了adminpermission范围,因为它不是必需的

我还对AdminRequirementHandler.cs进行了一些修改,但我会让您在我的回购协议中探讨这一点

基本上,我们已经确保用户声明在身份令牌中,通过这样做,用户声明就可以在您的AdminRequirementHandler中访问

希望这有帮助。

--编辑--

我已经修改了你的代码,解决了这个问题

这是我的回购协议的链接

为了修复您的解决方案,我还更改了服务器身份验证响应类型:-

"code Id_token"
在config.cs中的MVC客户端设置中,我添加了以下属性:-

 AlwaysSendClientClaims = true, 
 AlwaysIncludeUserClaimsInIdToken = true 
我还从mvc客户端删除了adminpermission范围,因为它不是必需的

我还对AdminRequirementHandler.cs进行了一些修改,但我会让您在我的回购协议中探讨这一点

基本上,我们已经确保用户声明在身份令牌中,通过这样做,用户声明就可以在您的AdminRequirementHandler中访问



希望这能有所帮助。

乍一看,我可以看到MVC应用程序没有管理员权限声明,您正在将它们作为作用域进行请求。您需要显示客户端和服务器的配置……您好@Derek,谢谢您的回复。我已经添加了Config.cs代码。所有自定义声明和角色都已添加到IdS CreateSuperuser方法中,唯一的作用域是“api1”。您可以在配置身份验证的位置添加客户端代码吗?因此,您可以使用Asp Identity为UserStore设置Idsvr4。创建用户的声明存储在Asp Identity user claims表中,但是您在将它们传输到MVC客户端时遇到问题吗?我认为您只需要为MVC客户端配置添加更多的作用域,您是否可以显示MVC客户端的代码,将其配置为使用Identity Server 4作为身份验证服务器?@RuardvanElburg,我已添加/更新了问题的更多信息。我不知道你是否已经被自动通知了,所以我想我应该试着提及你。我一眼就能看出,MVC应用程序没有管理员权限声明,你是作为作用域请求它们的。您需要显示客户端和服务器的配置……您好@Derek,谢谢您的回复。我已经添加了Config.cs代码。所有自定义声明和角色都已添加到IdS CreateSuperuser方法中,唯一的作用域是“api1”。您可以在配置身份验证的位置添加客户端代码吗?因此,您可以使用Asp Identity为UserStore设置Idsvr4。创建用户的声明存储在Asp Identity user claims表中,但是您在将它们传输到MVC客户端时遇到问题吗?我认为您只需要为MVC客户端配置添加更多的作用域,您是否可以显示MVC客户端的代码,将其配置为使用Identity Server 4作为身份验证服务器?@RuardvanElburg,我已添加/更新了问题的更多信息。我不知道你是否已经被自动通知了,所以我想我应该试着提及你。谢谢你,这帮了大忙。遗憾的是,这个问题仍然没有解决,但已经取得了进展,我更新了问题以反映这一点。在我看来,客户端现在拥有权限,但用户仍然无法通过客户端访问声明,因为授权处理程序的日志中显示的数据与以前相同。您可以向我显示AdminRights要求的代码吗?是的,有3个。行政许可;创建、更新、删除。AdminPermission Read位于AspNetRoleClaims中,正如我所读到的,此处的声明会自动添加到具有该角色的任何用户。我还添加了我认为与问题相关的当前数据。为授权处理程序添加了代码。授权要求仅包含类定义。非常感谢您的帮助和时间。当我看到你的答案时,我刚刚设法让它自己工作起来,我只是没有弄清楚什么代码不再需要。谢谢你,它帮了我很多忙。遗憾的是,这个问题仍然没有解决,但已经取得了进展,我更新了问题以反映这一点。看起来
public class AdminRequirementHandler : AuthorizationHandler<AdminRequirement>
{

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AdminRequirement requirement)
    {

        Console.WriteLine("User Identity: {0}", context.User.Identity);
        Console.WriteLine("Role is 'Administrator'? : {0}", context.User.IsInRole("Administrator"));
        Console.WriteLine("Identities of user:-");
        foreach (var v in context.User.Identities)
        {
            Console.WriteLine("\tName: {0},\tActor: {1},\tAuthType: {2},\tIsAuth: {3}", v.Name, v.Actor, v.AuthenticationType, v.IsAuthenticated);

            Console.WriteLine("\n\tClaims from Identity:-");
            foreach (var c in v.Claims)
                Console.WriteLine("\t\tType: {0},\tValue: {1},\tSubject: {2},\tIssuer: {3}", c.Type, c.Value, c.Subject, c.Issuer);
        }

        Console.WriteLine("Claims from other source:-");

        foreach(Claim c in context.User.Claims)
        {
            Console.WriteLine("\t\tType: {0},\tValue: {1},\tSubject: {2},\tIssuer: {3}", c.Type, c.Value, c.Subject, c.Issuer);
        }

        Console.WriteLine("\n *** Starting Authroization. ***\n");

        Claim
            role = context.User.FindFirst("role"),
            accessLevel = context.User.FindFirst("AdminPermission");


        if (role == null)
            Console.WriteLine("\tUser as no 'role' : '{0}'", role == null ? "null" : role.Value);
        else
            Console.WriteLine("\tUser has 'role' : '{0}'", role.Value);

        if (accessLevel == null)
            Console.WriteLine("\tUser has no claim 'AdminPermission' : '{0}'", accessLevel == null ? "null" : accessLevel.Value);
        else
            Console.WriteLine("\tUser has 'AdminPermission' : '{0}'", accessLevel.Value);

        if (role != null && accessLevel != null)
        {
            if (role.Value == "Administrator" && accessLevel.Value == "Read")
                context.Succeed(requirement);
        }
        else
            Console.WriteLine("\n *** Authorization Failue. ***\n");



        return Task.CompletedTask;
    }

}
ApiClaims                       : 
ApiResources                    : api1
ApiScopeClaims                  : AdminPermission, ApiScopeId = 2
ApiScopes                       : api1, ApiResourceId = 1
                                : AdminPermission, ApiResourceId = 1
ApiSecrets                      :
AspNetRoleClaims                : AdminPermission, Read, RoleId = b2f03...
AspNetRoles                     : Administrator, b2f03... 
                                : Customer, 779f7...
                                : Internal, 10d5d...
AspNetUserClaims                : AdminPermission, Create, UserId = 8ee62...
                                : AdminPermission, Update, UserId = 8ee62...
                                : AdminPermission, Delete, UserId = 8ee62...
AspNetUserLogins                :
AspNetUserRoles                 : UserId = 8ee62..., RoleId = b2f03... 
AspNetUsers                     : superuser@mail.com, Id = 8ee62...
AspNetUserTokens                :
ClientClaims                    :
ClientCorsOrigins               :
ClientGrantTypes                : hybrid, ClientId = 1
                                : client_credentials, ClientId = 1
                                : client_credentials, ClientId = 2
                                : password, ClientId = 3
ClientIdPRestrictions           :
ClientPostLogoutRedirectUris    : http://localhost:5002/signout-callback-oidc, ClientId = 1
ClientProperties                :
ClientRedirectUris              : http://localhost:5002/signin-oidc, ClientId = 1
Clients                         : mvc, AllowAccessTokenViaBrowser = 1, AllowOfflineAccess = 1, RequireConsent = 0
                                : client ...
                                : ro.client ...
ClientScopes                    : openid, ClientId = 1
                                : profile, ClientId = 1
                                : AdminPermission, ClientId = 1
ClientSecrets                   : Type = SharedSecret
IdentityClaims                  :   Id  IdentityResourceId  Type
                                    1   1                   sub
                                    2   2                   name
                                    3   2                   family_name
                                    4   2                   given_name
                                    5   2                   middle_name
                                    6   2                   nickname
                                    7   2                   preferred_username
                                    8   2                   profile
                                    9   2                   picture
                                    10  2                   website
                                    11  2                   gender
                                    12  2                   birthdate
                                    13  2                   zoneinfo
                                    14  2                   locale
                                    15  2                   updated_at
                                    16  3                   AdminPermission
IdentityResources               : openid
                                : profile
                                : AdminPermission
PersistedGrants                 : [8x] Type = refresh_token
"code Id_token"
 AlwaysSendClientClaims = true, 
 AlwaysIncludeUserClaimsInIdToken = true