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

时间:2020-07-03 19:39:37

标签: authentication asp.net-core-webapi jwt-auth

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

以下是已完成的步骤:

  1. 在以下位置的startup.cs中添加了app.UseAuthentication()
    Configure(IApplicationBuilder app, IHostingEnvironment env)
     {
        ......
        ......
        app.UseAuthentication();
     }
  1. 在同一项目中创建一个新的类文件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. 使用邮递员发送JSON数据,以及包含有效JWT令牌作为“载体”的授权标头。
  2. 代码只是忽略过滤器并处理控制器中的代码并返回结果

更多信息: 如果我将[Authorize]添加到控制器,Postman只会返回一个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;

Similar Issue - Link

如何使它工作?我想念什么吗?

1 个答案:

答案 0 :(得分:0)

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

在asp.net核心中,我们应该使用JWT熊身份验证中间件来满足您的要求。

您可以创建自定义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类,然后在startup.cs中注册该类。然后,您可以使用[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")]