使用JWT的.Net Core 2.0 Web API-添加身份信息会破坏JWT验证。

 2023-02-15    329  

问题描述

(编辑 – 找到正确的修复!请参阅下文)

确定 – 这是我的第一次尝试.NET Core 2.0和身份验证,尽管我过去已经用Web API 2.0完成了事物,并且在过去几年中的各种MVC和Webforms ASP项目中已经相当广泛地工作了.

使用JWT的.Net Core 2.0 Web API-添加身份信息会破坏JWT验证。

我正在尝试使用.NET核心创建一个Web API项目.这将形成一个多租户应用程序的后端,用于生成一些报告,因此我需要能够验证用户.似乎通常的方法是使用JWT – 首先验证用户生成令牌,然后将其传递给客户端以在每个API请求上使用.使用EF核心存储和检索数据.

我遵循这篇文章是一种基本的方式要获得此设置,我设法才能完成此操作确定 – 我有一个控制器接受用户名/密码,如果有效,则返回令牌,以及根据权利要求组成的一些授权策略.

我需要的下一件事是实际管理用户/密码/等.我以为我只是用.NET核心标识为此,我将有很多现成的代码担心用户/角色,密码等.我使用的是派生的自定义User class和UserRole类从标准IdentityUser和IdentityRole类,但是我从现在恢复到标准.

我所拥有的问题是,我不能弄清楚如何添加身份和注册所有各种服务(RoleManager,Usermanager等)而不破坏身份验证 – 基本上一旦我将此行添加到我的Startup.ConfigureServices类:

services.AddIdentity<IdentityUser, IdentityRole>()
    .AddEntityFrameworkStores<MyContext>();

这一切都出错了,当我收到请求时,我再也无法看到任何索赔,所以所有的政策只是锁定,你无法得到任何东西.

如果我没有这些行,那么我最终会出现与usermanager,rolemanager,userstore等相关的错误.

所以……如何(如果有可能)我可以将身份注册并正确挂钩,但避免/删除实际授权机制的任何更改?

我已经查看了一点在线,但很多这一点自从.NET核心1.x自了.NET Core 1.x所以很多教程等都不再有效.

我没有打算这个API应用程序拥有任何前端代码,因此我不需要任何cookie身份验证表单或现在任何东西.

编辑
好的,我现在发现在此代码中设置Startup.ConfigureServices()方法中的JWT身份验证:

services.AddAuthentication(
            JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                 >>breakpoint>>>   options.TokenValidationParameters =
                        new TokenValidationParameters
                        {
                            ValidateIssuer = true,
                            ValidateAudience = true,
                            ValidateLifetime = true,
                            ValidateIssuerSigningKey = true,

                            ValidIssuer = "Blah.Blah.Bearer",
                            ValidAudience = "Blah.Blah.Bearer",
                            IssuerSigningKey =
                            JwtSecurityKey.Create("verylongsecretkey")

                        };
                });

如果我在指示的行放置断点(通过”>>断点>>>”)然后当我 not 添加行以添加标识服务时,它会被命中,但如果我添加那些行,然后它永远不会击中.无论在方法中,我将services.AddIdentity()呼叫中的何处都是如此.我得到这只是一个lambda,所以它在稍后的点处被执行,但有没有办法我可以获得addiderity的东西来没有设置身份验证,或者使代码立即删除它?我在某些时候假设有一些代码,选择没有运行我在那里设置的Confif的兰姆达,因为身份的东西已经设置了…

感谢您阅读所有,如果您有:)

编辑 – 找到答案
好的,我最终发现这个GH问题基本上完全是这个问题:
https://github.com/aspnet/identity/issues/1376

基本上我要做的是双重的:

确保对services.AddIdentity<IdentityUser, IdentityContext()的呼叫进行了首先

更改呼叫以添加aude:

services.AddAuthentication(
            JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
...

到:

services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
            .AddJwtBearer(options =>
...

这会令人作呕地导致创建的cookie,但是,只要我可以告诉它,这不是用于身份验证 – 它纯粹是使用对控制器/动作的持票人令牌的求助令牌,这些控制器/动作有[Authorize(Policy = “Administrator”)]或类似集合至少.

我需要测试更多,如果我发现它没有以某种方式工作,我会尝试更新这个.

(编辑 – 将适当的解决方案放在答案中)

推荐答案

我最终将解决方案放在一起,所以关于用户的建议,始终是我编辑了我的帖子,我将其作为实际答案.

好的,这可以正确完成.首先,您需要使用我在上面的编辑中指出的身份验证选项 – 这很好.
然后,您需要使用services.AddIdentityCore<TUser>()而不是services.AddIdentity<TUser>().然而,这不会为角色管理添加一系列事物,并且显然缺少适当的构造函数,以便为您提供您要使用的角色类型.这意味着在我的情况下我必须这样做:

IdentityBuilder builder = services.AddIdentityCore<IdentityUser>(opt =>
        {
            opt.Password.RequireDigit = true;
            opt.Password.RequiredLength = 8;
            opt.Password.RequireNonAlphanumeric = false;
            opt.Password.RequireUppercase = true;
            opt.Password.RequireLowercase = true;
        }
        );
        builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services);
        builder
            .AddEntityFrameworkStores<MyContext>();
        //.AddDefaultTokenProviders();

        builder.AddRoleValidator<RoleValidator<IdentityRole>>();
        builder.AddRoleManager<RoleManager<IdentityRole>>();
        builder.AddSignInManager<SignInManager<IdentityUser>>();

如此,下一件事是确保在验证用户登录时(在发送令牌之前)时,请务必使用SignInManager方法CheckPasswordSignInAsync和 Not :

public async Task<IdentityUser> GetUserForLogin(string userName, string password)
    {   
        //find user first...
        var user = await _userManager.FindByNameAsync(userName);

        if (user == null)
        {
            return null;
        }

        //validate password...
        var signInResult = await _signInManager.CheckPasswordSignInAsync(user, password, false);

        //if password was ok, return this user.
        if (signInResult.Succeeded)
        {
            return user;
        }

        return null;
    }

如果使用PasswordSignInAsync方法,那么您将获得运行时错误.没有配置iaguthenticationsignInmandler.

我希望这有助于某人.

其他推荐答案

我已经从github中提取了AddIdentity代码,并创建了一个基于它的扩展方法,它不会添加默认cookie身份验证器,它现在非常类似于内置的AddIdentityCore,但可以接受.

/// <summary>
 /// Contains extension methods to <see cref="IServiceCollection"/> for configuring identity services.
 /// </summary>
 public static class IdentityServiceExtensions
 {
     /// <summary>
     /// Adds the default identity system configuration for the specified User and Role types. (Without Authentication Scheme)
     /// </summary>
     /// <typeparam name="TUser">The type representing a User in the system.</typeparam>
     /// <typeparam name="TRole">The type representing a Role in the system.</typeparam>
     /// <param name="services">The services available in the application.</param>
     /// <returns>An <see cref="IdentityBuilder"/> for creating and configuring the identity system.</returns>
     public static IdentityBuilder AddIdentityWithoutAuthenticator<TUser, TRole>(this IServiceCollection services)
         where TUser : class
         where TRole : class
         => services.AddIdentityWithoutAuthenticator<TUser, TRole>(setupAction: null);

     /// <summary>
     /// Adds and configures the identity system for the specified User and Role types. (Without Authentication Scheme)
     /// </summary>
     /// <typeparam name="TUser">The type representing a User in the system.</typeparam>
     /// <typeparam name="TRole">The type representing a Role in the system.</typeparam>
     /// <param name="services">The services available in the application.</param>
     /// <param name="setupAction">An action to configure the <see cref="IdentityOptions"/>.</param>
     /// <returns>An <see cref="IdentityBuilder"/> for creating and configuring the identity system.</returns>
     public static IdentityBuilder AddIdentityWithoutAuthenticator<TUser, TRole>(this IServiceCollection services, Action<IdentityOptions> setupAction)
         where TUser : class
         where TRole : class
     {
         // Hosting doesn't add IHttpContextAccessor by default
         services.AddHttpContextAccessor();
         // Identity services
         services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
         services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
         services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
         services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
         services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>();
         // No interface for the error describer so we can add errors without rev'ing the interface
         services.TryAddScoped<IdentityErrorDescriber>();
         services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
         services.TryAddScoped<ITwoFactorSecurityStampValidator, TwoFactorSecurityStampValidator<TUser>>();
         services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>();
         services.TryAddScoped<UserManager<TUser>>();
         services.TryAddScoped<SignInManager<TUser>>();
         services.TryAddScoped<RoleManager<TRole>>();

         if (setupAction != null)
         {
             services.Configure(setupAction);
         }

         return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
     }
 }

现在,您可以从WebAPI项目中使用上面的代码如此

.AddIdentityWithoutAuthenticator<User, IdentityRole>()

以上所述是小编给大家介绍的使用JWT的.Net Core 2.0 Web API-添加身份信息会破坏JWT验证。,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/33756.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。