C# Identity Server 4:向访问令牌添加声明
我正在使用Identity Server 4和隐式流,并希望向访问令牌添加一些声明,新声明或属性为“tenantId”和“langId” 我已经添加了langId作为我的作用域之一,如下所示,然后通过identity server请求它,但我也得到了租户ID。这怎么会发生 这是作用域和客户端配置的列表:C# Identity Server 4:向访问令牌添加声明,c#,jwt,identityserver4,openid-connect,thinktecture-ident-server,C#,Jwt,Identityserver4,Openid Connect,Thinktecture Ident Server,我正在使用Identity Server 4和隐式流,并希望向访问令牌添加一些声明,新声明或属性为“tenantId”和“langId” 我已经添加了langId作为我的作用域之一,如下所示,然后通过identity server请求它,但我也得到了租户ID。这怎么会发生 这是作用域和客户端配置的列表: public IEnumerable<Scope> GetScopes() { return new List<Scope>
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
},
};
}
解码访问令牌:
{
"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"
]
}
您应该检查并过滤掉未请求的声明。此答案是为.Net core 2上的IdentityServer 4编写的。若要将其用于.Net core 3,此答案可能会对您有所帮助,但您需要测试和更改一些内容。
我正在使用asp.net Identity and Entity Framework和IdentityServer 4 这是我的示例代码,运行良好,JWT包含所有角色和声明 您可以在这里看到如何使用ASP.Net核心标识实现Identityserver4 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?}");
});
}
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();
}
现在我可以在客户端web应用程序和API应用程序中使用[Authorize(Role=“SuperAdmin,Admin”)]
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();
经过一些严格的研究,我想提供我自己的答案: 在登录过程中,服务器将发出一个身份验证cookie,其中包含用户的一些声明 然后,客户端将在从cookie提供声明的同时请求访问令牌,配置文件服务将使用cookie声明生成访问令牌声明 接下来,客户端将请求一个id令牌,但这次它将使用来自访问令牌的声明 现在的问题是,identity server的默认配置文件服务仅通过使用access令牌中的声明来填充id令牌的声明,而ASP.Net identity的默认配置文件服务则从数据库存储中查找所有用户声明。这是一个令人困惑的问题 对于identity server实现,哪些声明最终会出现在访问令牌中?与作为API资源的作用域关联的声明,与id令牌中的声明相反,id令牌中的声明与作为标识资源的作用域关联 摘要 没有ASP.NET标识:
你是对的,我应该这样做,但这不是我的问题,因为如果我没有在上面的请求url中请求
langId
范围。返回的访问令牌既不包含langId
也不包含tenantId
(因此这里的过滤不是问题)。这就是我需要理解的,为什么在请求问题中的langId
时,访问令牌中包含租户ID。这是因为其他资源作用域没有分配任何声明,所以当您删除langId作用域时,此条件不会触发。这是什么版本的IdentityServer 4?“IdentityServer 4”:“1.0.0-rc1-update2“,您有没有可能为IS4 1.0最终版或1.2版更新此版本?还没有,为什么?有什么问题吗?有关访问令牌,请检查您的ApiResource的UserClaims。资料来源:干杯,垃圾桶。我不爱很多人,但你用这个答案让我的船漂浮。避免了身份声明的痛苦。我正在IdentityProfileService
中添加一个声明,它位于令牌中,您知道如何仅在特定客户端而不是在所有客户端中添加吗?。这是声明//添加更多类似的声明//声明.Add(new System.Security.claims.claims(“Balance”,user.Balance.ToString())代码>您好,William,是的,如果您不想添加声明或客户端声明,可以检查“context.client.ClientId”。我用它来查找我的租户,并在JWS中添加租户。@Mirak`GitHub上没有这些代码吗?或者有办法共享这些代码吗?我正在尝试在Identity Server 4中扮演角色,我有点迷路了,这将有助于我了解您的代码easier@AlexandraDamaschin不,我们有自己的私人TFS。我在很久以前就更改了这段代码,因为我们需要支持多租户,我们希望从数据库中读取Identity Server设置,并且我们从Core1.0迁移到了2.0.1。这段代码是我第一次研发Identity Server。
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;
}
}
}
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;
}
}
}
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?}");
});
}
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();
}
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();