首页 文章

Identity Server 4:向访问令牌添加声明

提问于
浏览
11

我正在使用Identity Server 4和Implicit Flow,并且想要向访问令牌添加一些声明,新的声明或属性是“tenantId”和“langId” .

我已将langId添加为我的范围之一,如下所示,然后通过身份服务器请求,但我也获得了tenantId . 怎么会发生这种情况?

这是范围列表和客户端配置:

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
            },
        };
    }

客户:

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"
                }
            }
        };

我在 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);
    }

这是我请求获取令牌,问题是我只是请求 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"
  ]
}

2 回答

  • 6

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

  • 25

    我在Identityserver4中使用asp.net Identity和Entity Framework .

    这是我的示例代码,效果很好,JWT包含所有角色和声明

    您可以在此处查看如何使用ASP.Net核心标识实现Identityserver4 http://docs.identityserver.io/en/release/quickstarts/6_aspnet_identity.html https://github.com/IdentityServer/IdentityServer4.Samples/tree/dev/Quickstarts/6_AspNetIdentity

    1-身份服务器startup.cs

    public void ConfigureServices(IServiceCollection services)
            {
                // Add framework services.
                services.AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    
                services.AddIdentity<ApplicationUser, IdentityRole>()
                    .AddEntityFrameworkStores<ApplicationDbContext>()
                    .AddDefaultTokenProviders();
    
                services.AddMvc();
    
                services.AddTransient<IEmailSender, AuthMessageSender>();
                services.AddTransient<ISmsSender, AuthMessageSender>();
    
                //Add IdentityServer services
                //var certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "LocalhostCert.pfx"), "123456");
                services.AddIdentityServer()
                        .AddTemporarySigningCredential()
                        .AddInMemoryIdentityResources(Configs.IdentityServerConfig.GetIdentityResources())
                        .AddInMemoryApiResources(Configs.IdentityServerConfig.GetApiResources())
                        .AddInMemoryClients(Configs.IdentityServerConfig.GetClients())
                        .AddAspNetIdentity<ApplicationUser>()
                        .AddProfileService<Configs.IdentityProfileService>();
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
            {
                loggerFactory.AddConsole(Configuration.GetSection("Logging"));
                loggerFactory.AddDebug();
    
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                    app.UseDatabaseErrorPage();
                    //app.UseBrowserLink();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                }
    
                app.UseStaticFiles();
    
                app.UseIdentity();
    
                // Adds IdentityServer
                app.UseIdentityServer();
    
                // Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715
    
                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller=Account}/{action=Login}/{id?}");
                });
    
            }
    

    2- IdentityServerConfig.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;
                }
    
            }
        }
    

    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 - 在我的客户端mvc核心项目中,我添加了3个nuget包

    .Microsoft.AspNetCore.Authentication.Cookies

    .Microsoft.AspNetCore.Authentication.OpenIdConnect

    .IdentityModel

    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 - 在我的API中,我添加了这个nuget包

    .IdentityServer4.AccessTokenValidatio

    和我的startup.cs是这样的

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
            {
                loggerFactory.AddConsole(Configuration.GetSection("Logging"));
                loggerFactory.AddDebug();
    
                //IdentityServer4.AccessTokenValidation
                app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
                {
                    Authority = "http://localhost:5000",
                    RequireHttpsMetadata = false,
                    ApiName = "ApplicationApi"
                });
    
                app.UseMvc();
            }
    

    现在我可以在客户端Web应用程序和API应用程序中使用[Authorize(Role =“SuperAdmin,Admin”)] .

    User.IsInRole("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();
    

相关问题