【问题标题】:Authentication in .NET Core 3.1: Default options provide too little control and don't work as expected.NET Core 3.1 中的身份验证:默认选项提供的控制太少,无法按预期工作
【发布时间】:2021-01-25 01:01:52
【问题描述】:

我正在 .NET Core 3.1 中使用 Identity 和 JWT 身份验证。我将来会添加 Open Id。我现在面临的问题是我对身份验证管道的控制太少了。管道会为您做出一些决定,例如何时重定向到登录。例如,对于身份验证,当您发出 401 状态时,它会尝试重定向到 /login - 即使您在 cookie 配置中指定了不同的页面。令人惊讶的是,JWT auth 也有同样的问题 - 即使提供的唯一策略是 Bearer 策略并且控制器被标记为 ApiController 属性。

[Authorize(AuthenticationSchemes = Schemes.Bearer)]

我想要完全控制管道和响应。通过尽可能多地利用内置工具来实现这一目标的最佳方法是什么?我不想编写自己的 JWT 验证代码,而是使用我配置的验证。

这就是我配置 JWT 的方式。 OnAuthenticationFailed。手动设置标头的回调永远不会运行。

 //piranha
        services.AddPiranha(options =>
        {
            options.UseFileStorage(naming: Piranha.Local.FileStorageNaming.UniqueFolderNames);
            options.UseImageSharp();
            options.UseManager();
            options.UseTinyMCE();
            options.UseMemoryCache();
            options.UseEF<SQLiteDb>(db =>
                db.UseSqlite("Filename=./Data/emurse-piranha.db"));
            options.UseIdentityWithSeed<IdentitySQLiteDb>(db =>
                db.UseSqlite("Filename=./Data/emurse-piranha.db"),
                identityOptions =>
                {
                    // Password settings
                    identityOptions.Password.RequireDigit = false;
                    identityOptions.Password.RequiredLength = 6;
                    identityOptions.Password.RequireNonAlphanumeric = false;
                    identityOptions.Password.RequireUppercase = false;
                    identityOptions.Password.RequireLowercase = false;
                    identityOptions.Password.RequiredUniqueChars = 1;

                    // Lockout settings
                    identityOptions.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
                    identityOptions.Lockout.MaxFailedAccessAttempts = 10;
                    identityOptions.Lockout.AllowedForNewUsers = true;

                    // User settings
                    identityOptions.User.RequireUniqueEmail = true;

                },
                cookieOptions =>
                {
                    cookieOptions.Cookie.HttpOnly = true;
                    cookieOptions.ExpireTimeSpan = TimeSpan.FromMinutes(30);
                    cookieOptions.LoginPath = "/manager/login";
                    cookieOptions.AccessDeniedPath = "/manager/login";
                    cookieOptions.SlidingExpiration = true;

                    var defaultAction = cookieOptions.Events.OnRedirectToLogin;
                    cookieOptions.Events.OnRedirectToLogin = (context) =>
                    {

                        if (context.Request.Path.Value.StartsWith("/api"))
                        {
                        response.StatusCode = 401;
                        response.BodyWriter.WriteAsync(new ReadOnlyMemory<byte> 
                        (Encoding.ASCII.GetBytes("unauthorized.")));
                        return Task.CompletedTask;
                        }
                        else
                        {
                            return defaultAction(context);
                        }
                    };

                });


            //turn off for prod
            options.AddRazorRuntimeCompilation=true;
            
        });

        //JWT
        services.AddAuthentication(Schemes.Bearer)
            .AddApplicationJwt(Configuration);
 public static AuthenticationBuilder AddApplicationJwt(this AuthenticationBuilder builder, IConfiguration config)
        {


            builder.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
            {
                var issuer = config["Jwt:Issuer"];
                var key = config["Jwt:Key"];

                options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = issuer,
                    ValidAudience = issuer,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key))
                };
                //Never executes
                options.Events= new JwtBearerEvents()
                {
                    OnAuthenticationFailed = ((context) =>         {
                       response.StatusCode = 401;
                       response.BodyWriter.WriteAsync(new ReadOnlyMemory<byte> 
                       (Encoding.ASCII.GetBytes("unauthorized.")));
                       return Task.CompletedTask;
                    }),
                     
                };
                 
            });

            return;
}   

然后使用大多数默认选项配置应用程序:

app.UseAuthorization();

        app.UsePiranha(options =>
        {
            options.UseTinyMCE();

            //default Auth middleware
            options.UseIdentity();

            app.UseCors(x => x
               .AllowAnyMethod()
               .AllowAnyHeader()
               .SetIsOriginAllowed(origin => true) //TODO: remove for production
               .AllowCredentials());
            //use Piranha manager                
            options.UseManager();
        });

【问题讨论】:

  • 什么是Schemes.Bearer?默认的 jwt 方案是JwtBearerDefaults.AuthenticationScheme
  • JwtBearerDefaults.AuthenticationScheme 只是一个字符串,Schemes.Bearer 设置为等于 JwtBearerDefaults.AuthenticationScheme ("Bearer")。
  • 我认为问题不在于发布的代码。我使用几乎相同的设置没有问题。你能多介绍一下你的身份验证/授权设置吗?
  • @Xerillio 我添加了一些代码,显示 Piranha 设置,这是配置 Auth 的地方。深入研究 .NET Core 和 Identity 源代码,希望我能很快获得更多见解。

标签: authentication .net-core jwt asp.net-identity asp.net-core-3.1


【解决方案1】:

感谢@Xerillio,我找到了问题的根本原因。在深入研究了源代码之后,我对扩展方法在后台做了什么有了更好的了解。

UseAuthentication 添加身份验证中间件。但是UseIdentity 也这样做了,UseIdentity 已经过时了。事实上,所有UseIdenitity 都会调用UseAuthentication

        app.UseStaticFiles();           
        app.UsePiranha();
        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();
        app.UsePiranhaIdentity();

        //TODO: remove for production
        app.UseCors(x => x
           .AllowAnyMethod()
           .AllowAnyHeader()
           .SetIsOriginAllowed(origin => true)
           .AllowCredentials()); 

        app.UsePiranhaManager();
        app.UsePiranhaTinyMCE();  

【讨论】:

  • 我不知道 Piranha,但您应该注意 UseIdentity 已过时,因此您应该尽量避免使用它。
猜你喜欢
  • 1970-01-01
  • 2020-11-14
  • 1970-01-01
  • 1970-01-01
  • 2020-06-05
  • 2017-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多