【问题标题】:JWT Authentication using a custom attribute in .NET Core Web API使用 .NET Core Web API 中的自定义属性进行 JWT 身份验证
【发布时间】:2019-12-14 00:10:51
【问题描述】:

我目前正在将我的 Web API 2.0 转换为 .NET Core Web API,但有一个部分我正在努力解决。

在我现有的 API 中,我有一个包含以下代码的属性:

public class JwtAuthentication : Attribute, IAuthenticationFilter
{
    public string Realm { get; set; }

    public bool AllowMultiple => false;

    public async Task AuthenticateAsync(
        HttpAuthenticationContext context, 
        CancellationToken cancellationToken)
    {
        var request = context.Request;

        var authorization = request.Headers.Authorization;

        // checking request header value having required scheme "Bearer" or not.
        if (authorization == null ||
            authorization.Scheme.ToLowerInvariant() != "bearer" ||
            string.IsNullOrEmpty(authorization.Parameter))
        {
            context.ErrorResult = new AuthenticationFailureResult("JWT Token is Missing", request);
            return;
        }

        // Getting Token value from header values.
        var token = authorization.Parameter;
        var principal = await AuthJwtToken(token);

        if (principal == null)
        {
            context.ErrorResult = new AuthenticationFailureResult("Invalid JWT Token", request);
        }
        else
        {
            context.Principal = principal;
        }
    }

    private static bool ValidateToken(string token, out ICollection<Claim> claims)
    {
        claims = null;

        var simplePrinciple = JwtAuthManager.GetPrincipal(token);

        if (simplePrinciple == null)
        {
            return false;
        }

        var identity = simplePrinciple.Identity as ClaimsIdentity;

        if (identity == null)
        {
            return false;
        }

        if (!identity.IsAuthenticated)
        {
            return false;
        }

        var usernameClaim = identity.FindFirst(ClaimTypes.Name);
        var emailClaim = identity.FindFirst(ClaimTypes.Email);

        var username = usernameClaim?.Value;
        var email = emailClaim?.Value;

        if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(email))
        {
            return false;
        }

        claims = identity.Claims.ToList();

        return true;
    }

    protected Task<IPrincipal> AuthJwtToken(string token)
    {
        if (ValidateToken(token, out var claims))
        {
            var identity = new ClaimsIdentity(claims, "Jwt");

            IPrincipal user = new ClaimsPrincipal(identity);

            return Task.FromResult(user);
        }

        return Task.FromResult<IPrincipal>(null);
    }

    public Task ChallengeAsync(
        HttpAuthenticationChallengeContext context, 
        CancellationToken cancellationToken)
    {
        Challenge(context);
        return Task.FromResult(0);
    }

    private void Challenge(HttpAuthenticationChallengeContext context)
    {
        string parameter = null;

        if (!string.IsNullOrEmpty(Realm))
        {
            parameter = "realm=\"" + Realm + "\"";
        }

        context.ChallengeWith("Bearer", parameter);
    }
}

如果我理解正确,在 ASP.NET Core 中,我所要做的就是在启动时定义以下内容:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>  
    {  
        options.TokenValidationParameters = new TokenValidationParameters  
        {  
            ValidateIssuer = true,  
            ValidateAudience = true,  
            ValidateLifetime = true,  
            ValidateIssuerSigningKey = true,  
            ValidIssuer = Configuration["Jwt:Issuer"],  
            ValidAudience = Configuration["Jwt:Issuer"],  
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))  
        };  
    });

我不确定我是否需要以下内容,但看起来像这样:

services.AddMvc(); 

我所能做的就是使用 [Authorize] 属性,但是如果我想复制我在 ASP.NET MVC Web API 2.0 中使用的属性怎么办?

我应该吗?我喜欢这样一个事实,即我可以看到令牌哪里出了问题。如果可以以相同的方式使用它并假设可以这样做,我该怎么做?在谷歌搜索解决方案时,我没有找到任何有用的信息?

谢谢。

【问题讨论】:

    标签: c# asp.net-web-api asp.net-core-webapi


    【解决方案1】:

    基于@dropoutcoder 的回答,

    由于options.Events 中的Events 为空,我收到了一个错误object reference not set...,为了解决这个问题,我使用了以下代码:

    options.Events = new JwtBearerEvents()
    {
        OnMessageReceived = context =>
        {
            return Task.CompletedTask;
        },
        OnAuthenticationFailed = context =>
        {
            return Task.CompletedTask;
        },
        OnTokenValidated = context =>
        {
            return Task.CompletedTask;
        },
        OnChallenge = context =>
        {
            return Task.CompletedTask;
        },
        OnForbidden = context =>
        {
            return Task.CompletedTask;
        }
    };
    

    【讨论】:

      【解决方案2】:

      我猜你不想重新发明整个不记名令牌认证轮。

      如果您想自定义事件的处理方式,您可以使用JwtBearerOptions.Events Property 将您自己的委托挂钩到其中的一个或多个。 (OnAuthenticationFailed PropertyOnChallenge PropertyOnMessageReceived PropertyOnTokenValidated Property)。

      身份验证失败记录示例。

      services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
          .AddJwtBearer(options =>  
          {  
              options.TokenValidationParameters = new TokenValidationParameters  
              {  
                  ValidateIssuer = true,  
                  ValidateAudience = true,  
                  ValidateLifetime = true,  
                  ValidateIssuerSigningKey = true,  
                  ValidIssuer = Configuration["Jwt:Issuer"],  
                  ValidAudience = Configuration["Jwt:Issuer"],  
                  IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))  
              };
      
          options.Events.OnAuthenticationFailed = (context) =>
          {
              // Log failed authentication here
      
              // Return control back to JWT Bearer middleware
              return Task.CompletedTask;
          }
      });
      

      希望对你有帮助

      【讨论】:

      • 抱歉耽搁了。这些事件正是我想要的。我会在几秒钟内检查其余的内容,但这绝对是一个好的开始。再次感谢。
      • 其实我说得很快。我收到一个错误System.NullReferenceException: 'Object reference not set to an instance of an object.',在 Microsoft 网站上进一步阅读后,它似乎只能兼容 .net core 2.2,除非他们的文档已过时。稍后会更新。
      猜你喜欢
      • 2018-08-09
      • 2020-04-22
      • 1970-01-01
      • 2018-02-27
      • 2018-03-15
      • 2018-03-01
      • 2020-10-15
      • 2020-01-30
      • 2020-05-20
      相关资源
      最近更新 更多