简体   繁体   English

身份服务器 4:向访问令牌添加声明

[英]Identity Server 4: adding claims to access token

I am using Identity Server 4 and Implicit Flow and want to add some claims to the access token, the new claims or attributes are "tenantId" and "langId".我正在使用 Identity Server 4 和隐式流,并想向访问令牌添加一些声明,新声明或属性是“tenantId”和“langId”。

I have added langId as one of my scopes as below and then requesting that through identity server, but i get the tenantId also.我已将 langId 添加为我的范围之一,如下所示,然后通过身份服务器请求它,但我也得到了租户 ID。 How can this happen?这怎么会发生?

This the list of scopes and client configuration:这是范围和客户端配置的列表:

  public IEnumerable<Scope> GetScopes()
    {
        return new List<Scope>
        {
             // standard OpenID Connect scopes
            StandardScopes.OpenId,
            StandardScopes.ProfileAlwaysInclude,
            StandardScopes.EmailAlwaysInclude,

            new Scope
            {
                Name="langId",
                 Description = "Language",
                Type= ScopeType.Resource,
                Claims = new List<ScopeClaim>()
                {
                    new ScopeClaim("langId", true)
                }
            },
            new Scope
            {
                Name = "resourceAPIs",
                Description = "Resource APIs",
                Type= ScopeType.Resource
            },
            new Scope
            {
                Name = "security_api",
                Description = "Security APIs",
                Type= ScopeType.Resource
            },
        };
    }

Client:客户:

  return new List<Client>
        {
            new Client
            {
                ClientName = "angular2client",
                ClientId = "angular2client",
                AccessTokenType = AccessTokenType.Jwt,
                AllowedGrantTypes = GrantTypes.Implicit,
                AllowAccessTokensViaBrowser = true,
                RedirectUris = new List<string>(redirectUris.Split(',')), 
                PostLogoutRedirectUris = new List<string>(postLogoutRedirectUris.Split(',')),
                AllowedCorsOrigins = new List<string>(allowedCorsOrigins.Split(',')),

                AllowedScopes = new List<string>
                {
                   "openid",
                   "resourceAPIs",
                   "security_api",         
                   "role",
                  "langId"
                }
            }
        };

I have added the claims in the ProfileService :我在ProfileService 中添加了声明:

 public class ProfileService : IdentityServer4.Services.IProfileService
{
    private readonly SecurityCore.ServiceContracts.IUserService _userService;


    public ProfileService(SecurityCore.ServiceContracts.IUserService userService)
    {
        _userService = userService;
    }

    public Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
       //hardcoded them just for testing purposes
        List<Claim> claims = new List<Claim>() { new Claim("langId", "en"), new Claim("tenantId", "123") };

        context.IssuedClaims = claims;


        return Task.FromResult(0);
    }

This is what i am requesting to get the token, the problem is i am only requesting the langId but I am getting both the tenantId and langId in the access token这就是我请求获得令牌,问题是我只请求LANGID但我在访问令牌获得两个tenantIdLANGID

http://localhost:44312/account/login?returnUrl=%2Fconnect%2Fauthorize%2Flogin%3Fresponse_type%3Did_token%2520token%26client_id%3Dangular2client%26redirect_uri%3Dhttp%253A%252F%252Flocalhost:5002%26scope%3DresourceAPIs%2520notifications_api%2520security_api%2520langId%2520navigation_api%2520openid%26nonce%3DN0.73617935552798141482424408851%26state%3D14824244088510.41368537145696305%26

Decoded access token:解码访问令牌:

 {
  "nbf": 1483043742,
  "exp": 1483047342,
  "iss": "http://localhost:44312",
  "aud": "http://localhost:44312/resources",
  "client_id": "angular2client",
  "sub": "1",
  "auth_time": 1483043588,
  "idp": "local",
  "langId": "en",
  "tenantId": "123",
  "scope": [
    "resourceAPIs",     
    "security_api",
    "langId",
    "openid"
  ],
  "amr": [
    "pwd"
  ]
}

This answer was written for Identityserver4 on .Net core 2 to use it for .Net core 3, this answer may help you, but you need to test and change a few things.这个答案是为 .Net core 2 上的 Identityserver4 编写的,用于 .Net core 3,这个答案可能对你有帮助,但你需要测试和更改一些东西。


I am using asp.net Identity and Entity Framework with Identityserver4. 我正在使用带有 Identityserver4 的 asp.net 身份和实体框架。

This is my sample code, works well and JWT contains all roles and claims这是我的示例代码,运行良好,JWT 包含所有角色和声明

You can see how to implement Identityserver4 with ASP.Net core identity here http://docs.identityserver.io/en/release/quickstarts/6_aspnet_identity.html https://github.com/IdentityServer/IdentityServer4.Samples/tree/dev/Quickstarts/6_AspNetIdentity您可以在此处查看如何使用 ASP.Net 核心身份实现 Identityserver4 http://docs.identityserver.io/en/release/quickstarts/6_aspnet_identity.html https://github.com/IdentityServer/IdentityServer4.Samples/tree/dev /快速入门/6_AspNetIdentity

1- identity server startup.cs 1-身份服务器startup.cs

using IdentityServer4;
    using IdentityServer4.Models;
    using System.Collections.Generic;

    namespace IdentityAuthority.Configs
    {

        public class IdentityServerConfig
        {

            // scopes define the resources in your system
            public static IEnumerable<IdentityResource> GetIdentityResources()
            {
                return new List<IdentityResource>
                {
                    new IdentityResources.OpenId(),
                    new IdentityResources.Profile()
                };
            }

            // scopes define the API resources
            public static IEnumerable<ApiResource> GetApiResources()
            {
                //Create api resource list
                List<ApiResource> apiResources = new List<ApiResource>();

                //Add Application Api API resource
                ApiResource applicationApi = new ApiResource("ApplicationApi", "Application Api");
                applicationApi.Description = "Application Api resource.";
                apiResources.Add(applicationApi);

                //Add Application Api API resource
                ApiResource definitionApi = new ApiResource("DefinitionApi", "Definition Api");
                definitionApi.Description = "Definition Api.";
                apiResources.Add(definitionApi);

                //Add FF API resource
                ApiResource ffApi = new ApiResource("FFAPI", "Fule .netfx API");
                ffApi.Description = "Test using .net 4.5 API application with IdentityServer3.AccessTokenValidation";
                apiResources.Add(ffApi);

                return apiResources;
            }

            // client want to access resources (aka scopes)
            public static IEnumerable<Client> GetClients()
            {
                //Create clients list like webui, console applications and...
                List<Client> clients = new List<Client>();

                //Add WebUI client
                Client webUi = new Client();
                webUi.ClientId = "U2EQlBHfcbuxUo";
                webUi.ClientSecrets.Add(new Secret("TbXuRy7SSF5wzH".Sha256()));
                webUi.ClientName = "WebUI";
                webUi.AllowedGrantTypes = GrantTypes.HybridAndClientCredentials;
                webUi.RequireConsent = false;
                webUi.AllowOfflineAccess = true;
                webUi.AlwaysSendClientClaims = true;
                webUi.AlwaysIncludeUserClaimsInIdToken = true;
                webUi.AllowedScopes.Add(IdentityServerConstants.StandardScopes.OpenId);
                webUi.AllowedScopes.Add(IdentityServerConstants.StandardScopes.Profile);
                webUi.AllowedScopes.Add("ApplicationApi");
                webUi.AllowedScopes.Add("DefinitionApi");
                webUi.AllowedScopes.Add("FFAPI");
                webUi.ClientUri = "http://localhost:5003";
                webUi.RedirectUris.Add("http://localhost:5003/signin-oidc");
                webUi.PostLogoutRedirectUris.Add("http://localhost:5003/signout-callback-oidc");
                clients.Add(webUi);

                //Add IIS test client
                Client iisClient = new Client();
                iisClient.ClientId = "b8zIsVfAl5hqZ3";
                iisClient.ClientSecrets.Add(new Secret("J0MchGJC8RzY7J".Sha256()));
                iisClient.ClientName = "IisClient";
                iisClient.AllowedGrantTypes = GrantTypes.HybridAndClientCredentials;
                iisClient.RequireConsent = false;
                iisClient.AllowOfflineAccess = true;
                iisClient.AlwaysSendClientClaims = true;
                iisClient.AlwaysIncludeUserClaimsInIdToken = true;
                iisClient.AllowedScopes.Add(IdentityServerConstants.StandardScopes.OpenId);
                iisClient.AllowedScopes.Add(IdentityServerConstants.StandardScopes.Profile);
                iisClient.AllowedScopes.Add("ApplicationApi");
                iisClient.AllowedScopes.Add("DefinitionApi");
                iisClient.AllowedScopes.Add("FFAPI");
                iisClient.ClientUri = "http://localhost:8080";
                iisClient.RedirectUris.Add("http://localhost:8080/signin-oidc");
                iisClient.PostLogoutRedirectUris.Add("http://localhost:8080/signout-callback-oidc");
                clients.Add(iisClient);

                return clients;
            }

        }
    }

2- IdentityServerConfig.cs 2- IdentityServerConfig.cs

using IdentityServer4.Services;
using System;
using System.Threading.Tasks;
using IdentityServer4.Models;
using IdentityAuthority.Models;
using Microsoft.AspNetCore.Identity;
using IdentityServer4.Extensions;
using System.Linq;

namespace IdentityAuthority.Configs
{
    public class IdentityProfileService : IProfileService
    {

        private readonly IUserClaimsPrincipalFactory<ApplicationUser> _claimsFactory;
        private readonly UserManager<ApplicationUser> _userManager;

        public IdentityProfileService(IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory, UserManager<ApplicationUser> userManager)
        {
            _claimsFactory = claimsFactory;
            _userManager = userManager;
        }

        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            var sub = context.Subject.GetSubjectId();
            var user = await _userManager.FindByIdAsync(sub);
            if (user == null)
            {
                throw new ArgumentException("");
            }

            var principal = await _claimsFactory.CreateAsync(user);
            var claims = principal.Claims.ToList();

            //Add more claims like this
            //claims.Add(new System.Security.Claims.Claim("MyProfileID", user.Id));

            context.IssuedClaims = claims;
        }

        public async Task IsActiveAsync(IsActiveContext context)
        {
            var sub = context.Subject.GetSubjectId();
            var user = await _userManager.FindByIdAsync(sub);
            context.IsActive = user != null;
        }
    }

}

3 - IdentityProfileService.cs 3 - IdentityProfileService.cs

 using IdentityServer4.Services; using System; using System.Threading.Tasks; using IdentityServer4.Models; using IdentityAuthority.Models; using Microsoft.AspNetCore.Identity; using IdentityServer4.Extensions; using System.Linq; namespace IdentityAuthority.Configs { public class IdentityProfileService : IProfileService { private readonly IUserClaimsPrincipalFactory<ApplicationUser> _claimsFactory; private readonly UserManager<ApplicationUser> _userManager; public IdentityProfileService(IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory, UserManager<ApplicationUser> userManager) { _claimsFactory = claimsFactory; _userManager = userManager; } public async Task GetProfileDataAsync(ProfileDataRequestContext context) { var sub = context.Subject.GetSubjectId(); var user = await _userManager.FindByIdAsync(sub); if (user == null) { throw new ArgumentException(""); } var principal = await _claimsFactory.CreateAsync(user); var claims = principal.Claims.ToList(); //Add more claims like this //claims.Add(new System.Security.Claims.Claim("MyProfileID", user.Id)); context.IssuedClaims = claims; } public async Task IsActiveAsync(IsActiveContext context) { var sub = context.Subject.GetSubjectId(); var user = await _userManager.FindByIdAsync(sub); context.IsActive = user != null; } } }

4 - In my client mvc core project I added 3 nuget packages 4 - 在我的客户端 mvc 核心项目中,我添加了 3 个 nuget 包

.Microsoft.AspNetCore.Authentication.Cookies .Microsoft.AspNetCore.Authentication.Cookies

.Microsoft.AspNetCore.Authentication.OpenIdConnect .Microsoft.AspNetCore.Authentication.OpenIdConnect

.IdentityModel .身份模型

5- This is my startup.cs in my client mvc core project 5- 这是我的客户端 mvc 核心项目中的 startup.cs

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); //app.UseBrowserLink(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); //Setup OpenId and Identity server app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationScheme = "Cookies", AutomaticAuthenticate = true }); app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions { Authority = "http://localhost:5000", ClientId = "U2EQlBHfcbuxUo", ClientSecret = "TbXuRy7SSF5wzH", AuthenticationScheme = "oidc", SignInScheme = "Cookies", SaveTokens = true, RequireHttpsMetadata = false, GetClaimsFromUserInfoEndpoint = true, ResponseType = "code id_token", Scope = { "ApplicationApi", "DefinitionApi", "FFAPI", "openid", "profile", "offline_access" }, TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters { NameClaimType = "name", RoleClaimType = "role" } }); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }

6 - In my API I added this nuget package 6 - 在我的 API 中,我添加了这个 nuget 包

.IdentityServer4.AccessTokenValidatio .IdentityServer4.AccessTokenValidatio

and my startup.cs is like this我的startup.cs是这样的

User.IsInRole("Admin")

Now I can use [Authorize(Role="SuperAdmin, Admin")] in both client web app and API app.现在我可以在客户端 Web 应用程序和 API 应用程序中使用 [Authorize(Role="SuperAdmin, Admin")]。

HttpContext.User.Claims 

var q = (from p in HttpContext.User.Claims where p.Type == "role" select p.Value).ToList();

var q2 = (from p in HttpContext.User.Claims where p.Type == "sub" select p.Value).First();

also I have access to claims我也有权获得索赔

HttpContext.User.Claims var q = (from p in HttpContext.User.Claims where p.Type == "role" select p.Value).ToList(); var q2 = (from p in HttpContext.User.Claims where p.Type == "sub" select p.Value).First();

您应该检查context.RequestedClaimTypes并过滤掉未请求的声明。

I would like to provide my own answer after some rigorous research:经过一些严谨的研究,我想提供我自己的答案:

During the login process, the server will issue an authentication cookie with some of the claims of the user.在登录过程中,服务器会发出一个带有用户声明的身份验证 cookie。

Then, the client will request an access token while providing the claims from the cookie, and the profile service will use the cookie claims to generate the access token claims.然后,客户端将在提供来自 cookie 的声明的同时请求访问令牌,并且配置文件服务将使用 cookie 声明来生成访问令牌声明。

Next, the client will request an id token, but this time it will use the claims from the access token.接下来,客户端将请求一个 id 令牌,但这次它将使用来自访问令牌的声明。

Now the thing is, the default profile service of identity server populates the claims of the id token just by using the claims in the access token, while the default profile service of ASP.Net Identity, does look up all the user claims from the database store.现在的情况是,身份服务器的默认配置文件服务仅通过使用访问令牌中的声明来填充 id 令牌的声明,而 ASP.Net Identity 的默认配置文件服务确实从数据库中查找所有用户声明店铺。 This is a point of confusion.这是一个混淆点。

For the identity server implementation, which claims end up in the access token?对于身份服务器实现,访问令牌中最终会出现哪些声明? The claims associated with scopes which are API resources, as opposed to the claims in the id token, which are those associated with scopes which are identity resources.与作为 API 资源的范围相关联的声明,与 id 令牌中的声明相反,后者是与作为身份资源的范围相关联的声明。

Summary概括

Without ASP.NET Identity:没有 ASP.NET 标识:

  1. Login - identity server issues a cookie with some claims登录 - 身份服务器发出带有某些声明的 cookie
  2. Access token query - identity server adds claims from the cookie based on requested api scopes访问令牌查询 - 身份服务器根据请求的 api 范围从 cookie 添加声明
  3. Id token query - identity server adds claims from the access token based on requested identity scopes Id 令牌查询 - 身份服务器根据请求的身份范围添加来自访问令牌的声明

With ASP.NET Identity:使用 ASP.NET 标识:

  1. Login - identity server issues a cookie with some claims登录 - 身份服务器发出带有某些声明的 cookie
  2. Access token query - identity server adds claims from the cookie based on requested api scopes访问令牌查询 - 身份服务器根据请求的 api 范围从 cookie 添加声明
  3. Id token query - identity server adds claims from the access token and the claims in the user store based on requested identity scopes Id 令牌查询 - 身份服务器根据请求的身份范围添加来自访问令牌的声明和用户存储中的声明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 身份服务器:在 MVC 客户端的混合流中添加对访问令牌的声明 - Identity Server: Add claims to access token in hybrid flow in MVC client 向身份服务器添加自定义声明4 GrantValidationResult - adding custom claims to identity server 4 GrantValidationResult 在身份服务器中使用配置文件服务添加声明导致身份验证过程中出现循环 - Adding claims with profile service in Identity server causing looping in the authentication process Identity Server 4 在从 UI 进行身份验证后添加声明 - Identity Server 4 Adding claims after authentication from a UI 如何使用 OIDC 在 Blazor 服务器应用程序中获取访问令牌声明? - How to get access token claims in a Blazor Server app using OIDC? Identity Server 4 为后续请求存储访问令牌 - Identity Server 4 store access token for subsequent requests Identity Server 4 无法验证我的访问令牌 - Identity Server 4 Cant Validate My Access Token 身份服务器 Windows 身份验证声明 - Identity Server Windows Authentication Claims 检查访问令牌是否有效 - Identity Server - Check if access token is valid - Identity Server Identity Server 3 + AspNet Identity 中基于角色的声明 - Role based claims in Identity Server 3 + AspNet Identity
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM