web-dev-qa-db-fra.com

Identity Server 4: ajout de revendications au jeton d'accès

J'utilise Identity Server 4 et Implicit Flow et je souhaite ajouter des revendications au jeton d'accès, les nouvelles revendications ou attributs sont "tenantId" et "langId".

J'ai ajouté langId comme l'une de mes étendues comme ci-dessous, puis je le demande via le serveur d'identité, mais j'obtiens également le tenantId. Comment cela peut-il arriver?

Voici la liste des étendues et de la configuration du client:

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

J'ai ajouté les revendications dans 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);
    }

C'est ce que je demande pour obtenir le jeton, le problème est que je ne demande que le langId mais je reçois les deux le tenantId et langId dans le jeton d'accès

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

Jeton d'accès décodé:

 {
  "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"
  ]
}
19
Hussein Salman

Vous devez vérifier context.RequestedClaimTypes et filtrer les revendications qui n'ont pas été demandées.

5
Aleksei Anufriev

J'utilise asp.net Identity and Entity Framework avec Identityserver4.

Ceci est mon exemple de code, fonctionne bien et JWT contient tous les rôles et revendications

Vous pouvez voir comment implémenter Identityserver4 avec l'identité principale ASP.Net ici http://docs.identityserver.io/en/release/quickstarts/6_aspnet_identity.htmlhttps: // github. com/IdentityServer/IdentityServer4.Samples/tree/dev/Quickstarts/6_AspNetIdentity

1- startup.cs du serveur d'identité

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 - Dans mon projet client mvc core, j'ai ajouté 3 paquets de pépites

.Microsoft.AspNetCore.Authentication.Cookies

.Microsoft.AspNetCore.Authentication.OpenIdConnect

.IdentityModel

5- Ceci est mon startup.cs dans mon projet principal mvc client

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 - Dans mon API j'ai ajouté ce paquet de pépites

.IdentityServer4.AccessTokenValidatio

et mon startup.cs est comme ça

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

Maintenant, je peux utiliser [Autoriser (Role = "SuperAdmin, Admin")] dans l'application Web cliente et l'application API.

User.IsInRole("Admin")

j'ai aussi accès aux réclamations

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();
37
Mohammad Karimi