6

Ich verwende Identity Server 4 und Implicit Flow und möchte dem Zugriffstoken einige Ansprüche hinzufügen, die neuen Ansprüche oder Attribute sind "tenantId" und "langId".Identity Server 4: Hinzufügen von Ansprüchen zum Zugriffstoken

Ich habe langId als einer meiner Bereiche wie folgt hinzugefügt und dann über Identity-Server, aber ich bekomme die TenantId auch. Wie kann das passieren?

Dies ist die Liste der Bereiche und Client-Konfiguration:

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

Auftraggeber:

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

Ich habe die Ansprüche in der Profile hinzugefügt:

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

Dies ist, was Ich bitte um den Token, das Problem ist, ich bin onl y Auffordern der LANGID aber ich bin immer sowohl die tenantId und im Zugangs LANGID Token

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 Zugriffstoken:

{ 
    "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" 
    ] 
} 
+0

Welche Version von IdentityServer4 ist das? – Rafe

+0

"IdentityServer4": "1.0.0-rc1-update2", – Coding

+0

Haben Sie eine Chance, dass Sie dies für IS4 1.0 final oder Version 1.2 aktualisiert haben? – Rafe

Antwort

5

Sie sollte überprüfen context.RequestedClaimTypes und fi Verfiltern von Ansprüchen, die nicht angefordert wurden.

+0

Sie haben Recht, ich sollte das tun, aber das ist nicht mein Problem, weil, wenn ich den 'langId' Anwendungsbereich nicht angefordert habe in der Anfrage URL oben. Das zurückgegebene Zugriffstoken enthält weder 'langId' noch' tenantId' (daher ist das Filtern hier nicht das Problem). Und das ist es, was ich verstehen muss, warum beim Anfordern der "langId" wie in der Frage die mandentId im Zugriffstoken enthalten war. – Coding

+1

Dies liegt daran, dass anderen Ressourcenbereichen keine Ansprüche zugewiesen sind. Wenn Sie also den langId-Bereich entfernen, https://github.com/IdentityServer/IdentityServer4/blob/dev/src/IdentityServer4/Services/DefaultClaimsService.cs# L183 Zustand feuert nicht. –

16

Ich benutze asp.net Identität und Entity Framework mit Identityserver4.

Dies ist mein Beispielcode funktioniert gut und JWT enthält alle Rollen und behauptet

Sie sehen können, wie Identityserver4 mit ASP.Net Kernidentität hier http://docs.identityserver.io/en/release/quickstarts/6_aspnet_identity.html https://github.com/IdentityServer/IdentityServer4.Samples/tree/dev/Quickstarts/6_AspNetIdentity

1- Identität Serverstart implementieren 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 meinem Klienten mvc Kernprojekt hinzugefügt I 3 nuget Pakete

.Microsoft.AspNetCore.Authentication.Cookies

.Microsoft.AspNetCore .Authentication.OpenIdConnect

.IdentityModel

5- Dies ist mein Startup.cs in meinem Klienten mvc Kernprojekt

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 meiner API ich dieses nuget Paket

.IdentityServer4.AccessTokenValidatio

hinzugefügt

und meine startup.cs wie diese

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

Jetzt kann ich [Authorize (Role = "SuperAdmin, Admin")] sowohl in der Client-Web-App als auch in der API-App verwenden.

User.IsInRole("Admin") 

auch habe ich Zugriff auf Ansprüche

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(); 
+1

Prost mucker. Ich liebe nicht viele, aber du treibst mein Boot mit dieser Antwort. Identitätsbehauptungsschmerz abgewendet. – no1spirite

+1

Ich füge einen Anspruch in 'IdentityProfileService' hinzu und es ist im Token, weißt du, wie man nur in einem bestimmten Client und nicht in allen Clients hinzugefügt wird? Dies ist der Anspruch '// Fügen Sie weitere Ansprüche wie folgt hinzu //claims.Add(new System.Security.Claims.Claim (" Balance ", user.Balance.ToString()));' –

+0

Hallo William, Ja, wenn Sie keine Ansprüche oder Ansprüche für einen Kunden hinzufügen möchten, können Sie die "context.Client.ClientId" überprüfen. Ich benutze dies, um meine TenantId zu finden, die eine Mieter-ID in JWS hinzufügt. – Mirak

Verwandte Themen