自定义身份验证过滤器问题 asp.net 核心

Issue with custom Authentication filter asp.net core

我正在尝试在 ASP.NET Core 中创建自定义身份验证过滤器。需要在控制器中使用它来验证提供给我的 JWT 并创建 Claim Principal。但是,当我将身份验证标签放在控制器上方时,什么也没有发生,控制器在没有身份验证的情况下得到处理。

以下是已完成的步骤:

  1. 下的 startup.cs 中添加了 app.UseAuthentication()
    Configure(IApplicationBuilder app, IHostingEnvironment env)
     {
        ......
        ......
        app.UseAuthentication();
     }
  1. 在同一项目中创建了一个新的 class 文件 ProcessAuth,其中包含 AuthenticationAsync 和 ChallengeAsync
   public class ProcessAuth : Attribute, IAuthenticationFilter
    {
        public bool AllowMultiple { get { return false; } }


        public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
        {            
            HttpRequestMessage request = context.Request;
            AuthenticationHeaderValue authorization = request.Headers.Authorization;
            
            // More code to be added for validating the JWT
        }

        public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
        {
            throw new NotImplementedException(); //sample code
        }
    } 
  1. 在控制器中添加了对这个新文件的引用
  2. 将标签 [ProcessAuth] 放在控制器的顶部
    [ProcessAuth]
    [Route("api/[controller]")]
    [ApiController] 
  1. 使用 Postman 发送 JSON 数据,以及包含有效 JWT 令牌作为“Bearer”的授权 Header
  2. 代码只是忽略了控制器中的过滤器和处理代码,returns结果

更多信息: 如果我将 [Authorize] 添加到控制器,Postman 只需 returns a 401 Unauthorized error

也检查了 this URL,但找不到问题。

更新: 我检查了类似 Stack Overflow 问题的答案并遵循了相同的答案,但问题仍然存在。

安装的 Nuget 包: Microsoft.AspNet.WebApi.Core 还有 Microsoft.AspNet.WebApi

使用的命名空间:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Filters;
using System.Web.Http.Controllers;

如何让它工作?我错过了什么吗?

根据您的代码,我发现您在 asp.net 核心应用程序中使用了 asp.net 身份验证过滤器。这是行不通的。

在asp.net核心中,我们应该使用JWT bear认证中间件来实现你的要求。

您可以创建自定义 OnChallenge 来验证 jwt 令牌和 OnTokenValidated 来添加声明。

更多详情,您可以参考以下代码:

        services.AddAuthentication(auth =>
        {
            auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(token =>
        {
            token.RequireHttpsMetadata = false;
            token.SaveToken = true;
            token.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                //Same Secret key will be used while creating the token
                IssuerSigningKey = new SymmetricSecurityKey(SecretKey),
                ValidateIssuer = true,
                //Usually, this is your application base URL
                ValidIssuer = "http://localhost:45092/",
                ValidateAudience = true,
                //Here, we are creating and using JWT within the same application.
                //In this case, base URL is fine.
                //If the JWT is created using a web service, then this would be the consumer URL.
                ValidAudience = "http://localhost:45092/",
                RequireExpirationTime = true,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
            };

            token.Events = new JwtBearerEvents { 
                
                 OnChallenge = async ctx => { 
                 
                 },
                  OnTokenValidated = async ctx =>
                  {
                      //Get the calling app client id that came from the token produced by Azure AD
                      string clientId = ctx.Principal.FindFirstValue("appid");

                      //Get EF context
                      //var db = ctx.HttpContext.RequestServices.GetRequiredService<AuthorizationDbContext>();

                      //Check if this app can read confidential items
                      bool canReadConfidentialItems = await db.Applications.AnyAsync(a => a.ClientId == clientId && a.ReadConfidentialItems);
                      if (canReadConfidentialItems)
                      {
                          //Add claim if yes
                          var claims = new List<Claim>
                {
                    new Claim("ConfidentialAccess", "true")
                };
                          var appIdentity = new ClaimsIdentity(claims);

                          ctx.Principal.AddIdentity(appIdentity);
                      }
                  }
            };
        });

编辑:

您可以像下面这样创建 AuthenticationHandler 和 AuthenticationSchemeOptions class 并在 startup.cs 中注册 class。然后你可以使用 [Authorize(AuthenticationSchemes = "Test")] 来设置特殊的 AuthenticationSchemes。

更多细节,您可以参考下面的代码示例:

public class ValidateHashAuthenticationSchemeOptions : AuthenticationSchemeOptions
{

}

public class ValidateHashAuthenticationHandler
: AuthenticationHandler<ValidateHashAuthenticationSchemeOptions>
{
    public ValidateHashAuthenticationHandler(
        IOptionsMonitor<ValidateHashAuthenticationSchemeOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder,
        ISystemClock clock)
        : base(options, logger, encoder, clock)
    {
    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        //TokenModel model;

        // validation comes in here
        if (!Request.Headers.ContainsKey("X-Base-Token"))
        {
            return Task.FromResult(AuthenticateResult.Fail("Header Not Found."));
        }

        var token = Request.Headers["X-Base-Token"].ToString();

        try
        {
            // convert the input string into byte stream
            using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(token)))
            {
                // deserialize stream into token model object
                //model = Serializer.Deserialize<TokenModel>(stream);
            }
        }
        catch (System.Exception ex)
        {
            Console.WriteLine("Exception Occured while Deserializing: " + ex);
            return Task.FromResult(AuthenticateResult.Fail("TokenParseException"));
        }

        //if (model != null)
        //{
        //    // success case AuthenticationTicket generation
        //    // happens from here

        //    // create claims array from the model
        //    var claims = new[] {
        //        new Claim(ClaimTypes.NameIdentifier, model.UserId.ToString()),
        //        new Claim(ClaimTypes.Email, model.EmailAddress),
        //        new Claim(ClaimTypes.Name, model.Name) };

        //    // generate claimsIdentity on the name of the class
        //    var claimsIdentity = new ClaimsIdentity(claims,
        //                nameof(ValidateHashAuthenticationHandler));

        //    // generate AuthenticationTicket from the Identity
        //    // and current authentication scheme
        //    var ticket = new AuthenticationTicket(
        //        new ClaimsPrincipal(claimsIdentity), this.Scheme.Name);

        //    // pass on the ticket to the middleware
        //    return Task.FromResult(AuthenticateResult.Success(ticket));
        //}

        return Task.FromResult(AuthenticateResult.Fail("Model is Empty"));
    }

}
public class TokenModel
{
    public int UserId { get; set; }
    public string Name { get; set; }
    public string EmailAddress { get; set; }
}

Startup.cs 将以下代码添加到 ConfigureServices 方法中:

            services.AddAuthentication(options =>
            {
                options.DefaultScheme
                    = "Test";
            })
.AddScheme<ValidateHashAuthenticationSchemeOptions, ValidateHashAuthenticationHandler>
        ("Test", null);

控制器:

[Authorize(AuthenticationSchemes = "Test")]