简体   繁体   English

在 .NET Core Web API 中使用自定义属性的 JWT 身份验证

[英]JWT Authentication using a custom attribute in .NET Core Web API

I'm currently converting my Web API 2.0 to .NET Core Web API but there is one section I'm struggling with.我目前正在将我的 Web API 2.0 转换为 .NET Core Web API,但有一个部分我正在努力解决。

In my existing API, I have an attribute with the following code:在我现有的 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);
    }
}

If I understand correctly, in ASP.NET Core, all I have to do is define the following in my startup:如果我理解正确,在 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"]))  
        };  
    });

and I'm not sure whether or not I'll need the below but it looks like it:我不确定我是否需要以下内容,但它看起来像:

services.AddMvc(); 

and all I could do is use the [Authorize] attribute but what if I want to replicate the Attribute I used in my ASP.NET MVC Web API 2.0?我所能做的就是使用 [Authorize] 属性,但是如果我想复制我在 ASP.NET MVC Web API 2.0 中使用的属性怎么办?

Should I?我是不是该? I like the fact that I can see where things have gone wrong with the token.我喜欢这样一个事实,即我可以看到令牌出现问题的地方。 If it can be used the same way and assuming it is OK to do so, how do I do this?如果可以以相同的方式使用它并假设可以这样做,我该怎么做? I haven't found anything that would help when googling for a solution?在谷歌搜索解决方案时,我没有找到任何有用的东西?

Thanks.谢谢。

Based on @dropoutcoder answer,基于@dropoutcoder 的回答,

As Events in options.Events is null, I was getting an error object reference not set... and to get around this problem I used the following instead:由于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;
    }
};

I guess you don't want to reinvent the whole bearer token authentication wheel.我猜您不想重新发明整个不记名令牌身份验证轮。

In case you'd like to customize how events are handled you can use JwtBearerOptions.Events Property to hook your own delegates to one or more of them.如果您想自定义事件的处理方式,您可以使用JwtBearerOptions.Events 属性将您自己的委托挂接到其中的一个或多个。 ( OnAuthenticationFailed Property , OnChallenge Property , OnMessageReceived Property , OnTokenValidated Property ). OnAuthenticationFailed 属性OnChallenge 属性OnMessageReceived 属性OnTokenValidated 属性)。

Example failed authentication logging.示例失败的身份验证日志记录。

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;
    }
});

Hope it helps希望能帮助到你

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM