【问题标题】:IdentityServer4 return unknown claims using OpenIdIdentityServer4 使用 OpenId 返回未知声明
【发布时间】:2020-04-09 10:31:41
【问题描述】:

我从is4aspid 模板(使用 ASP.NET Identity 进行用户管理的基本 IdentityServer)创建了一个 IdentityServer4 服务器,它带有 2 个示例用户。

之后,我按照IdentityServer4 docs 的说明创建了一个剃须刀页面客户端。

应用程序可以工作,但应用程序从身份服务器未知声明中获取,它们是 (type=value):

s_hash=tFpbakJatWNQIjaChraJAw
sid=Sj6JGUgztjOIK1Cq8E-HoA
sub=a070c8cc-d962-440c-a796-e0c169e87578
auth_time=1586427090
idp=local
amr=pwd

我在 appsettings.json 上将服务器客户端定义为:

{

  "ClientId": "mvc",
  "Enabled": true,
  "ClientName": "Mvc Client",

  "AllowedGrantTypes": [ "client_credentials", "authorization_code" ],
  "RequirePkce": true,
  "ClientSecrets": [ { "Value": "hide_for_privacity" } ],

  "RedirectUris": [ "https://localhost:5001/signin-oidc" ],
  "FrontChannelLogoutUri": "http://localhost:5001/signout-oidc",
  "PostLogoutRedirectUris": [ "http://localhost:5001/signout-callback-oidc" ],

  "AllowOfflineAccess": true,
  "AllowedScopes": [ "openid", "profile", "offline_access", "api1" ]
}

客户端的认证设置如下:

services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(options =>
{
    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.Authority = "http://localhost:5099";
    options.RequireHttpsMetadata = false;
    options.ClientId = "mvc";
    options.ClientSecret = "hide_for_privacity";
    options.ResponseType = "code";
    options.UsePkce = true;
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("offline_access");
    options.SaveTokens = true;
});

我已经使用 jwt.io 解码了返回的令牌,它是有效负载:

{
  "nbf": 1586427096,
  "exp": 1586427396,
  "iss": "http://localhost:5099",
  "aud": "mvc",
  "nonce": "637220238868623664.MzdjNjI0NmMtNWNhMy00YTg4LWIzYTUtYjcxMTFmMTNlYjhiYWY0ZmM5NTQtNDY1Mi00ZWVhLTlkNjUtY2UzMzIwMjY5NjA4",
  "iat": 1586427096,
  "at_hash": "Z_Cwm-4UzmH8v8PyW2d0Rg",
  "s_hash": "tFpbakJatWNQIjaChraJAw",
  "sid": "Sj6JGUgztjOIK1Cq8E-HoA",
  "sub": "a070c8cc-d962-440c-a796-e0c169e87578",
  "auth_time": 1586427090,
  "idp": "local",
  "amr": ["pwd"]
}

为什么我没有收到服务器中定义的用户名和角色??

【问题讨论】:

    标签: asp.net-core identityserver4 dotnetopenauth


    【解决方案1】:

    首先要确认您已将角色添加到数据库并将角色添加到用户。在 SeedData.cs 中,您可以播种以下角色:

    public static void SeedRoles(RoleManager<IdentityRole> roleManager)
    {
        if (!roleManager.RoleExistsAsync("NormalUser").Result)
        {
            IdentityRole role = new IdentityRole();
            role.Name = "NormalUser";
    
            IdentityResult roleResult = roleManager.
            CreateAsync(role).Result;
        }
    
    
        if (!roleManager.RoleExistsAsync("Administrator").Result)
        {
            IdentityRole role = new IdentityRole();
            role.Name = "Administrator";
    
            IdentityResult roleResult = roleManager.
            CreateAsync(role).Result;
        }
    }
    

    并在EnsureSeedData函数中为用户添加角色:

    ...
    SeedRoles(roleMgr);
    var alice = userMgr.FindByNameAsync("alice").Result;
    if (alice == null)
    {
        alice = new ApplicationUser
        {
            UserName = "alice"
        };
        var result = userMgr.CreateAsync(alice, "Pass123$").Result;
    
        if (!result.Succeeded)
        {
            throw new Exception(result.Errors.First().Description);
        }
        userMgr.AddToRoleAsync(alice,"NormalUser").Wait();
        ...
    }
    

    之后,您可以向令牌添加自定义声明:

    public class ProfileService : IProfileService
    {
        protected readonly UserManager<ApplicationUser> _userManager;
    
    
        public ProfileService(UserManager<ApplicationUser> userManager)
        {
            _userManager = userManager;
        }
    
        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            ApplicationUser user = await _userManager.GetUserAsync(context.Subject);
    
            IList<string> roles = await _userManager.GetRolesAsync(user);
    
            IList<Claim> roleClaims = new List<Claim>();
            foreach (string role in roles)
            {
                roleClaims.Add(new Claim(JwtClaimTypes.Role, role));
            }
    
            //add user claims
    
            roleClaims.Add(new Claim(JwtClaimTypes.Name, user.UserName));
            context.IssuedClaims.AddRange(roleClaims);
        }
    
        public Task IsActiveAsync(IsActiveContext context)
        {
            return Task.CompletedTask;
        }
    }
    

    并在 Startup.cs 中注册:

    var builder = services.AddIdentityServer(options =>
    {
        options.Events.RaiseErrorEvents = true;
        options.Events.RaiseInformationEvents = true;
        options.Events.RaiseFailureEvents = true;
        options.Events.RaiseSuccessEvents = true;
    })
    .AddInMemoryIdentityResources(Config.Ids)
    .AddInMemoryApiResources(Config.Apis)
    .AddInMemoryClients(Config.Clients)
    .AddAspNetIdentity<ApplicationUser>()
    .AddProfileService<ProfileService>();   <-- add this line
    

    Config.cs 中,在您的客户端配置中,将 AlwaysIncludeUserClaimsInIdToken 设置为 true 以使声明在 ID toke 中可用:

    AlwaysIncludeUserClaimsInIdToken=true, 
    

    现在声明在 ID Token 中,您还可以更改客户端应用程序中的 OIDC 配置以使用来自令牌的 JwtClaimTypes.Role 类型设置角色声明:

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-11
    • 2019-10-24
    • 2019-03-21
    相关资源
    最近更新 更多