Identity Server 4: adding claims to access token

瘦欲@ 提交于 2019-11-29 20:29:54

You should check context.RequestedClaimTypes and filter out claims, that were not requested.

I am using asp.net Identity and Entity Framework with Identityserver4.

This is my sample code, works well and JWT contains all roles and claims

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

1- identity server 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 - In my client mvc core project I added 3 nuget packages

.Microsoft.AspNetCore.Authentication.Cookies

.Microsoft.AspNetCore.Authentication.OpenIdConnect

.IdentityModel

5- This is my startup.cs in my client mvc core project

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

.IdentityServer4.AccessTokenValidatio

and my startup.cs is like this

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();
        }

Now I can use [Authorize(Role="SuperAdmin, Admin")] in both client web app and API app.

User.IsInRole("Admin")

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();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!