本文介绍了ASP.NET 样板 + IdentityServer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I tried to implement IdentityServer as it is explained at https://aspnetboilerplate.com/Pages/Documents/Zero/Identity-Server

但是示例不起作用.

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

I started a Core 2.0 Angular project from ASP.NET Boilerplate. Is there any updated working sample based on the documentation?

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

There is more than one problem, but one of them is with AuthConfigurer.cs.

API 调用方(客户端)无法通过令牌验证.

The API caller (client) cannot pass the token validation.

其实在TokenAuthController.cs中有一个令牌生成代码:

Actually, there is a token generation code in TokenAuthController.cs:

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 类中,AddIdentityAddAuthentication 创建不同的令牌值和验证规则.

But in the Startup class, AddIdentity and AddAuthentication create different token values and validation rules.

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 客户端调用,如下所示:

The token can be generated by both sides. CreateAccessToken is called by the Angular client and by the API client as shown below:

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");

但只有其中一个(根据身份验证部分)无法通过身份验证.

But just one of them (according to the Authentication part) cannot pass authentication.

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

I need both the API client authentication and the Angular client authentication to work.

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

I have some clue from a link about dual authentication:
https://wildermuth.com/2017/08/19/Two-AuthorizationSchemes-in-ASP-NET-Core-2

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

But I could not solve this. Any comment is very valuable to solve the problem.

推荐答案

在我和我设法解决的问题这里是需要的修改;

At the and I managed to solve problem here are the needed modifications;

1-在TokenAuthController中有一个令牌创建代码,如下所示;

1- in the TokenAuthController there is a token creation code as shown below;

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 来自登录的声明与当前实现完全不同,并且子"声明已添加到声明中.所以没有必要单独添加.所以请更新这个,如下所示

If you start using Identityserver Claims coming from login is totally different from current implementation and "sub" claim is already added to claims. So it is not necessary to add seperately. So please update this as shown below

 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;最重要的部分是 authenticationSchemaName "IdentityBearer" 不要忘记添加它.

2- Add Authentcation to startup class as shown below; The most important part is authenticationSchemaName "IdentityBearer" do not forget adding it.

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

3- 但这还不够.因为如果您在启动身份验证中查看配置方法,则注册为

3- But this is not enough. because if you look at configure methon in startup authontication is registered as

app.UseJwtTokenMiddleware();

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

if you check it it uses "bearer" schema not IdentityBearer as we added above. So we also need anpther authenticaiton registration. Add this line too (have both of them)

    app.UseJwtTokenMiddleware("IdentityBearer");

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

4- But as you can see there is no method taking string parameter to add UseJwtTokenMiddleware so it is needed to update that class to. please change your class as shown below;

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 客户端登录创建的.如果您调试每个请求都尝试通过其中的两个,但只有一个成功,这对您来说就足够了.

Now you have now two different token type and two different validator. YOu can have API client using basic token info and JWT tokens are created by login from angular client. if you debug each request tries to pass two of them but just one of them succeed which is enough for you.

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

if aspnetboilerplate team updates sample according to this requirement it would be great.

这篇关于ASP.NET 样板 + IdentityServer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 02:22