Identity Server 4: Добавление утверждений к маркеру доступа
Я использую Identity Server 4 и неявный поток и хочу добавить некоторые утверждения к маркеру доступа, новыми утверждениями или атрибутами являются "tenantId"и " langId".
Я добавил langId в качестве одной из моих областей, как показано ниже, а затем запросил это через identity server, но я также получаю 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);
}
Это то, что я прошу, чтобы получить маркер, проблема в том, что я прошу только лангид но я получаю и то и другое. тенантид и еще лангид в маркере доступа
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
Декодированный маркер доступа:
{
"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 ответа:
Вы должны проверить контекст .RequestedClaimTypes и отфильтровать утверждения, которые не были запрошены.
Я использую asp.net Identity and Entity Framework с Identityserver4.
Это мой пример кода, хорошо работает, и JWT содержит все роли и утверждения
Вы можете увидеть, как реализовать Identityserver4 с помощью ASP.Net основная идентичность здесь http://docs.identityserver.io/en/release/quickstarts/6_aspnet_identity.html https://github.com/IdentityServer/IdentityServer4.Samples/tree/dev/Quickstarts/6_AspNetIdentity
1-сервер идентификации запуск.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 core я добавил 3 пакета nuget
.Microsoft.Аспнеткор.Идентификация.Печенье
.Microsoft.Аспнеткор.Идентификация.OpenIdConnect
.IdentityModel
[7]}5 - это мой стартап.cs в моем клиенте MVC core projectpublic 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
И мой стартап.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(); }
Теперь я могу использовать [Authorize (Role= "SuperAdmin, Admin")] Как в клиентском веб-приложении, так и в API-приложении.
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();