ASP.NET 样板 + IdentityServer
ASP.NET Boilerplate + IdentityServer
我尝试实现 IdentityServer,如 https://aspnetboilerplate.com/Pages/Documents/Zero/Identity-Server
中所述
但是示例不起作用。
我从 ASP.NET Boilerplate 开始了一个 Core 2.0 Angular 项目。是否有任何基于文档的更新工作示例?
问题不止一个,但其中一个是 AuthConfigurer.cs.
API调用方(客户端)无法通过令牌验证。
其实TokenAuthController.cs中有一个token生成代码:
private string CreateAccessToken(IEnumerable<Claim> claims, TimeSpan? expiration = null)
{
var now = DateTime.UtcNow;
var jwtSecurityToken = new JwtSecurityToken(
issuer: _configuration.Issuer,
audience: _configuration.Audience,
claims: claims,
notBefore: now,
expires: now.Add(expiration ?? _configuration.Expiration),
signingCredentials: _configuration.SigningCredentials
);
return new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
}
但在 Startup
class、AddIdentity
和 AddAuthentication
中创建不同的令牌值和验证规则。
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources())
.AddInMemoryApiResources(IdentityServerConfig.GetApiResources())
.AddInMemoryClients(IdentityServerConfig.GetClients())
.AddAbpPersistedGrants<IAbpPersistedGrantDbContext>()
.AddAbpIdentityServer<User>(); ;
services.AddAuthentication().AddIdentityServerAuthentication("IdentityBearer", options =>
{
options.Authority = "http://localhost:62114/";
options.RequireHttpsMetadata = false;
});
令牌可以由双方生成。 CreateAccessToken
由 Angular 客户端和 API 客户端调用,如下所示:
var disco = await DiscoveryClient.GetAsync("http://localhost:21021");
var httpHandler = new HttpClientHandler();
httpHandler.CookieContainer.Add(new Uri("http://localhost:21021/"), new Cookie(MultiTenancyConsts.TenantIdResolveKey, "1")); //Set TenantId
var tokenClient = new TokenClient(disco.TokenEndpoint, "AngularSPA", "secret", httpHandler);
var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("admin", "123qwe", "default-api"); //RequestClientCredentialsAsync("default-api");
但只有其中一个(根据Authentication部分)不能通过认证
我需要 API 客户端身份验证和 Angular 客户端身份验证才能工作。
我从 link 那里得到了一些关于双重身份验证的线索:
https://wildermuth.com/2017/08/19/Two-AuthorizationSchemes-in-ASP-NET-Core-2
但是我无法解决这个问题。任何评论对解决问题都很有价值
我设法解决了这里需要修改的问题;
1-在 TokenAuthController 中有一个令牌创建代码,如下所示;
private static List<Claim> CreateJwtClaims(ClaimsIdentity identity)
{
var claims = identity.Claims.ToList();
var nameIdClaim = claims.First(c => c.Type == ClaimTypes.NameIdentifier);
// Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
claims.AddRange(new[]
{
new Claim(JwtRegisteredClaimNames.Sub, nameIdClaim.Value),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
});
return claims;
}
如果您开始使用 Identityserver,来自登录的声明与当前的实现完全不同,并且 "sub" 声明已添加到声明中。所以没有必要单独添加。所以请更新如下所示
private static List<Claim> CreateJwtClaims(ClaimsIdentity identity)
{
var claims = identity.Claims.ToList();
// Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
claims.AddRange(new[]
{
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
});
return claims;
}
2- 将Authentcation 添加到启动class 如下所示;最重要的部分是 authenticationSchemaName "IdentityBearer" 不要忘记添加它。
services.AddAuthentication().AddIdentityServerAuthentication("IdentityBearer", options =>
{
options.Authority = "http://localhost:21021/";
options.RequireHttpsMetadata = false;
});
3-但这还不够。因为如果你在启动时查看配置方法,authontication 被注册为
app.UseJwtTokenMiddleware();
如果你检查它,它使用 "bearer" 模式而不是我们上面添加的 IdentityBearer。所以我们还需要anpther authenticaiton注册。也添加这一行(两者都有)
app.UseJwtTokenMiddleware("IdentityBearer");
4- 但是如您所见,没有采用字符串参数来添加 UseJwtTokenMiddleware 的方法,因此需要将 class 更新为。请如下所示更改您的 class;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
namespace MyProject.Authentication.JwtBearer
{
public static class JwtTokenMiddleware
{
public static IApplicationBuilder UseJwtTokenMiddleware(this IApplicationBuilder app)
{
return UseJwtTokenMiddleware(app, JwtBearerDefaults.AuthenticationScheme);
}
public static IApplicationBuilder UseJwtTokenMiddleware(this IApplicationBuilder app, string authenticationScheme)
{
return app.Use(async (ctx, next) =>
{
if (ctx.User.Identity?.IsAuthenticated != true)
{
var result = await ctx.AuthenticateAsync(authenticationScheme);
if (result.Succeeded && result.Principal != null)
{
ctx.User = result.Principal;
}
}
await next();
});
}
}
}
现在你有两个不同的令牌类型和两个不同的验证器。您可以让 API 客户端使用基本令牌信息,而 JWT 令牌是通过从 angular 客户端登录创建的。如果您调试每个请求,则尝试传递其中两个,但只有其中一个成功,这对您来说已经足够了。
如果 aspnetboilerplate 团队根据此要求更新示例,那就太好了。
我尝试实现 IdentityServer,如 https://aspnetboilerplate.com/Pages/Documents/Zero/Identity-Server
中所述但是示例不起作用。
我从 ASP.NET Boilerplate 开始了一个 Core 2.0 Angular 项目。是否有任何基于文档的更新工作示例?
问题不止一个,但其中一个是 AuthConfigurer.cs.
API调用方(客户端)无法通过令牌验证。
其实TokenAuthController.cs中有一个token生成代码:
private string CreateAccessToken(IEnumerable<Claim> claims, TimeSpan? expiration = null)
{
var now = DateTime.UtcNow;
var jwtSecurityToken = new JwtSecurityToken(
issuer: _configuration.Issuer,
audience: _configuration.Audience,
claims: claims,
notBefore: now,
expires: now.Add(expiration ?? _configuration.Expiration),
signingCredentials: _configuration.SigningCredentials
);
return new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
}
但在 Startup
class、AddIdentity
和 AddAuthentication
中创建不同的令牌值和验证规则。
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources())
.AddInMemoryApiResources(IdentityServerConfig.GetApiResources())
.AddInMemoryClients(IdentityServerConfig.GetClients())
.AddAbpPersistedGrants<IAbpPersistedGrantDbContext>()
.AddAbpIdentityServer<User>(); ;
services.AddAuthentication().AddIdentityServerAuthentication("IdentityBearer", options =>
{
options.Authority = "http://localhost:62114/";
options.RequireHttpsMetadata = false;
});
令牌可以由双方生成。 CreateAccessToken
由 Angular 客户端和 API 客户端调用,如下所示:
var disco = await DiscoveryClient.GetAsync("http://localhost:21021");
var httpHandler = new HttpClientHandler();
httpHandler.CookieContainer.Add(new Uri("http://localhost:21021/"), new Cookie(MultiTenancyConsts.TenantIdResolveKey, "1")); //Set TenantId
var tokenClient = new TokenClient(disco.TokenEndpoint, "AngularSPA", "secret", httpHandler);
var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("admin", "123qwe", "default-api"); //RequestClientCredentialsAsync("default-api");
但只有其中一个(根据Authentication部分)不能通过认证
我需要 API 客户端身份验证和 Angular 客户端身份验证才能工作。
我从 link 那里得到了一些关于双重身份验证的线索:
https://wildermuth.com/2017/08/19/Two-AuthorizationSchemes-in-ASP-NET-Core-2
但是我无法解决这个问题。任何评论对解决问题都很有价值
我设法解决了这里需要修改的问题;
1-在 TokenAuthController 中有一个令牌创建代码,如下所示;
private static List<Claim> CreateJwtClaims(ClaimsIdentity identity)
{
var claims = identity.Claims.ToList();
var nameIdClaim = claims.First(c => c.Type == ClaimTypes.NameIdentifier);
// Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
claims.AddRange(new[]
{
new Claim(JwtRegisteredClaimNames.Sub, nameIdClaim.Value),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
});
return claims;
}
如果您开始使用 Identityserver,来自登录的声明与当前的实现完全不同,并且 "sub" 声明已添加到声明中。所以没有必要单独添加。所以请更新如下所示
private static List<Claim> CreateJwtClaims(ClaimsIdentity identity)
{
var claims = identity.Claims.ToList();
// Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
claims.AddRange(new[]
{
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
});
return claims;
}
2- 将Authentcation 添加到启动class 如下所示;最重要的部分是 authenticationSchemaName "IdentityBearer" 不要忘记添加它。
services.AddAuthentication().AddIdentityServerAuthentication("IdentityBearer", options =>
{
options.Authority = "http://localhost:21021/";
options.RequireHttpsMetadata = false;
});
3-但这还不够。因为如果你在启动时查看配置方法,authontication 被注册为
app.UseJwtTokenMiddleware();
如果你检查它,它使用 "bearer" 模式而不是我们上面添加的 IdentityBearer。所以我们还需要anpther authenticaiton注册。也添加这一行(两者都有)
app.UseJwtTokenMiddleware("IdentityBearer");
4- 但是如您所见,没有采用字符串参数来添加 UseJwtTokenMiddleware 的方法,因此需要将 class 更新为。请如下所示更改您的 class;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
namespace MyProject.Authentication.JwtBearer
{
public static class JwtTokenMiddleware
{
public static IApplicationBuilder UseJwtTokenMiddleware(this IApplicationBuilder app)
{
return UseJwtTokenMiddleware(app, JwtBearerDefaults.AuthenticationScheme);
}
public static IApplicationBuilder UseJwtTokenMiddleware(this IApplicationBuilder app, string authenticationScheme)
{
return app.Use(async (ctx, next) =>
{
if (ctx.User.Identity?.IsAuthenticated != true)
{
var result = await ctx.AuthenticateAsync(authenticationScheme);
if (result.Succeeded && result.Principal != null)
{
ctx.User = result.Principal;
}
}
await next();
});
}
}
}
现在你有两个不同的令牌类型和两个不同的验证器。您可以让 API 客户端使用基本令牌信息,而 JWT 令牌是通过从 angular 客户端登录创建的。如果您调试每个请求,则尝试传递其中两个,但只有其中一个成功,这对您来说已经足够了。
如果 aspnetboilerplate 团队根据此要求更新示例,那就太好了。