ASP.NET 样板 + IdentityServer

Tuğ*_*aya 3 c# asp.net-core aspnetboilerplate identityserver4 angular

我尝试实现 IdentityServer,如https://aspnetboilerplate.com/Pages/Documents/Zero/Identity-Server中所述

但该示例不起作用。

我从 ASP.NET Boilerplate 启动了一个 Core 2.0 Angular 项目。是否有基于文档的更新工作示例?

问题不止一个,但其中之一是AuthConfigurer.cs

API调用方(客户端)无法通过token验证。

实际上, 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);
}
Run Code Online (Sandbox Code Playgroud)

但在Startup类中,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;
});
Run Code Online (Sandbox Code Playgroud)

令牌可以由双方生成。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");
Run Code Online (Sandbox Code Playgroud)

但只有其中之一(根据认证部分)无法通过认证。

我需要 API 客户端身份验证和 Angular 客户端身份验证才能工作。

我从有关双重身份验证的链接中得到了一些线索:
https://wildermuth.com/2017/08/19/Two-AuthorizationSchemes-in-ASP-NET-Core-2

但我无法解决这个问题。任何评论对于解决问题都是非常有价值的。

Tuğ*_*aya 5

我设法解决了这里的问题,并进行了必要的修改;

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;
        }
Run Code Online (Sandbox Code Playgroud)

如果您开始使用 Identityserver,来自登录的声明与当前的实现完全不同,并且“子”声明已添加到声明中。所以没必要单独添加。所以请更新如下所示

 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;
        }
Run Code Online (Sandbox Code Playgroud)

2-将Authentcation添加到启动类中,如下所示;最重要的部分是authenticationSchemaName“IdentityBearer”不要忘记添加它。

services.AddAuthentication().AddIdentityServerAuthentication("IdentityBearer", options =>
            {
                options.Authority = "http://localhost:21021/";
                options.RequireHttpsMetadata = false;
            });
Run Code Online (Sandbox Code Playgroud)

3-但这还不够。因为如果你看看启动身份验证中的配置方法被注册为

app.UseJwtTokenMiddleware(); 
Run Code Online (Sandbox Code Playgroud)

如果你检查它,它使用“承载”模式而不是我们上面添加的 IdentityBearer 。所以我们还需要另外的认证注册。也添加这一行(两者都有)

    app.UseJwtTokenMiddleware("IdentityBearer");
Run Code Online (Sandbox Code Playgroud)

4-但是正如您所看到的,没有使用字符串参数来添加 UseJwtTokenMiddleware 的方法,因此需要更新该类。请如下所示更改您的班级;

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();
            });
        }        
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您有两种不同的令牌类型和两个不同的验证器。您可以拥有使用基本令牌信息的 API 客户端,并且 JWT 令牌是通过从角度客户端登录创建的。如果您调试每个请求,都会尝试传递其中两个请求,但只有其中一个成功,这对您来说就足够了。

如果 aspnetboilerplate 团队根据此要求更新示例,那就太好了。