asp.net-mvc - JWT 身份验证 ASP.NET Core MVC 应用程序

标签 asp.net-mvc asp.net-core jwt

我已经看到了许多关于如何在 Angular、React、Vue 等客户端中使用 JWT 身份验证的示例,但找不到任何在 ASP.NET Core(特别是 2.2)Web App Mvc 中使用 JWT 身份验证的示例。

有没有人有任何关于如何做到这一点的例子或建议?

谢谢,

最佳答案

You can use this class based on nuget package JWT 3.0.3


using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using Newtonsoft.Json;
using System;

namespace Common.Utils
{
  public class JwtToken
  {
    private IJwtEncoder encoder;
    private IJwtDecoder decoder;

    /// <remarks>
    /// This requires a key value randomly generated and stored in your configuration settings. 
    /// Consider that it is a good practice use keys as at least long as the output digest bytes 
    /// length produced by the hashing algorithm used. Since we use an HMAC-SHA-512 algorithm, 
    /// then we can provide it a key at least 64 bytes long.
    /// <see cref="https://tools.ietf.org/html/rfc4868#page-7"/>
    /// </remarks>
    public string SecretKey { get; set; } 

    public JwtToken()
    {
        IJwtAlgorithm algorithm = new HMACSHA512Algorithm();
        IJsonSerializer serializer = new JsonNetSerializer();
        IDateTimeProvider datetimeProvider = new UtcDateTimeProvider();
        IJwtValidator validator = new JwtValidator(serializer, datetimeProvider);
        IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();

        encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
        decoder = new JwtDecoder(serializer, validator, urlEncoder);
        SecretKey = "";
    }

    public JwtToken(string secretKey) : this()
    {
        SecretKey = secretKey;
    }

    public bool IsTokenValid(string token)
    {
        return !string.IsNullOrWhiteSpace(DecodeToken(token));
    }

    public string GetToken(object payload)
    {
        try
        {
            return encoder.Encode(payload, SecretKey);
        }
        catch (Exception)
        {
            return encoder.Encode(new DataModel(payload), SecretKey);
        }
    }

    public string DecodeToken(string token)
    {
        try
        {
            if (string.IsNullOrWhiteSpace(token) || token == "null")
            {
                return null;
            }
            return decoder.Decode(token, SecretKey, true);
        }
        catch (TokenExpiredException)
        {
            return null;
        }
        catch (SignatureVerificationException)
        {
            return null;
        }
    }

    public T DecodeToken<T>(string token) where T : class
    {
        try
        {
            if (string.IsNullOrWhiteSpace(token))
            {
                return null;
            }
            return decoder.DecodeToObject<T>(token, SecretKey, true);
        }
        catch (TokenExpiredException)
        {
            return null;
        }
        catch (SignatureVerificationException)
        {
            return null;
        }
        catch (Exception)
        {
            var data = decoder.DecodeToObject<DataModel>(token, SecretKey, true).Data;
            return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(data));
        }
    }
  }

  public class DataModel
  {
    public DataModel(object data)
    {
        Data = data;
    }
    public object Data { get; set; }
  }
}

Then in your Startup class Configure method set the jwt middleware for check authentication status of each request:


app.Use((context, next) =>
        {

            // verify app access token if not another service call
            var appAccessToken = context.Request.Headers["Authorization"];
            if (appAccessToken.Count == 0)
            {
                context.Items["User"] = null;
            }
            else
            {
                var token = appAccessToken.ToString().Replace("Bearer ", "");
                var jwtToken = new JwtToken(config.JwtTokenSecret); //you need a secret (with requirements specified above) in your configuration (db, appsettings.json)
                if (string.IsNullOrWhiteSpace(token) || !jwtToken.IsTokenValid(token))
                {
                    context.Response.StatusCode = 401;
                    return Task.FromResult(0);
                }

                dynamic user = jwtToken.DecodeToken<dynamic>(token);

                var cachedToken = cache.Get(user.Id);  //you need some cache for store your token after login success and so can check against
                if (cachedToken == null || cachedToken.ToString() != token)
                {
                    context.Response.StatusCode = 401;
                    return Task.FromResult(0);
                }

                context.Items["User"] = new Dictionary<string, string>() {
                        { "FullName",user.Name?.ToString()},
                        { "FirstName",user.FirstName?.ToString()},
                        { "LastName",user.LastName?.ToString()},
                        { "Role",user.Role?.ToString()},
                        { "Email",user.Email?.ToString()}
                    };
            }
            return next();
        });

And finally you need generate the token and return it after authentication:


    [AllowAnonymous]
    public IActionResult Login(string username, string password)
    {
        User user = null; //you need some User class with the structure of the previous dictionary
        if (checkAuthenticationOK(username, password, out user)) //chackAuthenticationOk sets the user against db data after a succesfull authentication
        {
           var token = new JwtToken(_config.JwtTokenSecret).GetToken(user);  //_config is an object to your configuration
           _cache.Set(user.id, token);  //store in the cache the token for checking in each request
           return Ok(token);
        }

        return StatusCode(401, "User is not authorized");
    }

关于asp.net-mvc - JWT 身份验证 ASP.NET Core MVC 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54559562/

相关文章:

c# - 容器如何实际解析 ILogger<T>

c# - 如何从 ASP.NET Core 中的 .json 文件读取 AppSettings 值

python - Oauth2 身份验证 token 包含 Azure 应用程序 ID 的 OID,而不是用户 ID

javascript - js-routes ASP.NET MVC 替代方案

asp.net-mvc - jQuery UI 对话框不会关闭

jquery - 如何从 DatePicker ui jquery 中删除时间

c# - 用对象数组修补对象

java - MVC4 验证在 IIS 部署后不起作用,但在 Visual Studio 服务器中工作正常

ruby-on-rails - 解码 JavaScript 网络 token (JWT) 的到期日期?

node.js - 表达限制资源属于特定用户的优雅方式