我正在使用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 但我得到的是 tenantId访问令牌中 和 langId
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"
]
}
答案 0 :(得分:34)
我正在使用带有Identityserver4的asp.net身份和实体框架。
这是我的示例代码,效果很好,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();
}
现在我可以在客户端网络应用和API应用中使用[授权(角色=&#34; SuperAdmin,管理员&#34;)]。
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();
答案 1 :(得分:5)
您应该检查context.RequestedClaimTypes并过滤掉未请求的声明。
答案 2 :(得分:0)
经过一些严格的研究,我想提供自己的答案:
在登录过程中,服务器将发出带有用户某些声明的身份验证cookie。
然后,客户端将在提供cookie声明的同时请求访问令牌,并且配置文件服务将使用cookie声明来生成访问令牌声明。
接下来,客户端将请求一个id令牌,但是这次它将使用访问令牌中的声明。
现在的事情是,身份服务器的默认配置文件服务仅使用访问令牌中的声明来填充id令牌的声明,而ASP.Net Identity的默认配置文件服务确实会查找所有用户声明从数据库存储中。这是一个困惑点。
对于身份服务器实现,哪个声明最终出现在访问令牌中?与作为API资源的范围相关联的声明(与id令牌中与作为身份资源的范围相关联的声明相反)。
摘要
没有ASP.NET身份:
具有ASP.NET身份: