阅读 236

NET CORE项目中JWT的使用

NET CORE项目中JWT的使用

一、自定义CheckJWTAttribute特性方式

之前使用的是这种方式,根据jwt原理自定义生成JWT、验证jwt,感觉挺好。原理就是自定义一个拦截器(特性),拦截器对每个请求都优先进行处理,认证成功的进行下一步操作。

1、定义JWTPayload类

复制代码

using System;namespace HyDataMiddleground.Util
{    public class JWTPayload
    {        public string UserName { get; set; }        public string Email { get; set; }        public string UserId { get; set; }        public DateTime Expire { get; set; }
    }
}

复制代码

 

2、定义CheckJWTAttribute特性

用于验证jwt:

复制代码

using Microsoft.AspNetCore.Mvc.Filters;using System;using System.Threading.Tasks;namespace HyDataMiddleground.Util
{    /// <summary>
    /// JWT校检    /// </summary>
    public class CheckJWTAttribute : BaseActionFilterAsync
    {        private static readonly int _errorCode = 401;        public override async Task OnActionExecuting(ActionExecutingContext context)
        {            if (context.ContainsFilter<NoCheckJWTAttribute>()) return;            try
            {                var req = context.HttpContext.Request;                string token = req.GetToken();                if (token.IsNullOrEmpty())
                {
                    context.Result = Error("缺少token", _errorCode);                    return;
                }                if (!JWTHelper.CheckToken(token, JWTHelper.JWTSecret))
                {
                    context.Result = Error("token校检失败!", _errorCode);                    return;
                }                var payload = JWTHelper.GetPayload<JWTPayload>(token);                if (payload.Expire < DateTime.Now)
                {
                    context.Result = Error("token过期!", _errorCode);                    return;
                }
            }            catch (Exception ex)
            {
                context.Result = Error(ex.Message, _errorCode);
            }            await Task.CompletedTask;
        }
    }
}

复制代码

3、定义其他帮助类

(1)BaseActionFilterAsync类

复制代码

using Microsoft.AspNetCore.Mvc;using Microsoft.AspNetCore.Mvc.Filters;using System;using System.Threading.Tasks;namespace HyDataMiddleground.Util
{    public class BaseActionFilterAsync : Attribute, IAsyncActionFilter
    {        /// <summary>
        /// action执行之前执行        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async virtual Task OnActionExecuting(ActionExecutingContext context)
        {            await Task.CompletedTask;
        }        /// <summary>
        /// action执行之后执行        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async virtual Task OnActionExecuted(ActionExecutedContext context)
        {            await Task.CompletedTask;
        }        /// <summary>
        /// 在模型绑定完成后,在操作之前异步调用。        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {            await OnActionExecuting(context);            if (context.Result == null)
            {                var nextContext = await next();                await OnActionExecuted(nextContext);
            }
        }        /// <summary>
        /// 返回JSON        /// </summary>
        /// <param name="json">json字符串</param>
        /// <returns></returns>
        public ContentResult JsonContent(string json)
        {            return new ContentResult { Content = json, StatusCode = 200, ContentType = "application/json; charset=utf-8" };
        }        /// <summary>
        /// 返回成功        /// </summary>
        /// <returns></returns>
        public ContentResult Success()
        {
            AjaxResult res = new AjaxResult
            {
                Success = true,
                Msg = "请求成功!"
            };            return JsonContent(res.ToJson());
        }        /// <summary>
        /// 返回成功        /// </summary>
        /// <param name="msg">消息</param>
        /// <returns></returns>
        public ContentResult Success(string msg)
        {
            AjaxResult res = new AjaxResult
            {
                Success = true,
                Msg = msg
            };            return JsonContent(res.ToJson());
        }        /// <summary>
        /// 返回成功        /// </summary>
        /// <param name="data">返回的数据</param>
        /// <returns></returns>
        public ContentResult Success<T>(T data)
        {
            AjaxResult<T> res = new AjaxResult<T>
            {
                Success = true,
                Msg = "请求成功!",
                Data = data
            };            return JsonContent(res.ToJson());
        }        /// <summary>
        /// 返回错误        /// </summary>
        /// <returns></returns>
        public ContentResult Error()
        {
            AjaxResult res = new AjaxResult
            {
                Success = false,
                Msg = "请求失败!"
            };            return JsonContent(res.ToJson());
        }        /// <summary>
        /// 返回错误        /// </summary>
        /// <param name="msg">错误提示</param>
        /// <returns></returns>
        public ContentResult Error(string msg)
        {
            AjaxResult res = new AjaxResult
            {
                Success = false,
                Msg = msg,
            };            return JsonContent(res.ToJson());
        }        /// <summary>
        /// 返回错误        /// </summary>
        /// <param name="msg">错误提示</param>
        /// <param name="errorCode">错误代码</param>
        /// <returns></returns>
        public ContentResult Error(string msg, int errorCode)
        {
            AjaxResult res = new AjaxResult
            {
                Success = false,
                Msg = msg,
                ErrorCode = errorCode
            };            return JsonContent(res.ToJson());
        }
    }
}

复制代码

(2)AjaxResult类

复制代码

namespace HyDataMiddleground.Util
{    /// <summary>
    /// Ajax请求结果    /// </summary>
    public class AjaxResult
    {        /// <summary>
        /// 是否成功        /// </summary>
        public bool Success { get; set; } = true;        /// <summary>
        /// 错误代码        /// </summary>
        public int ErrorCode { get; set; }        /// <summary>
        /// 返回消息        /// </summary>
        public string Msg { get; set; }
    }
}

复制代码

(3)上述代码中使用到的扩展类Extention

复制代码

    
         
        = =  Func<JsonSerializerSettings>(() =>
                setting.DateFormatHandling ==  
         
         
         
           ToJson(

复制代码

(4)JWTHelper类

复制代码

using Newtonsoft.Json.Linq;namespace HyDataMiddleground.Util
{    /// <summary>
    /// JWT帮助类    /// </summary>
    public class JWTHelper
    {        private static readonly string _headerBase64Url = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}".Base64UrlEncode();        public static readonly string JWTSecret = ConfigHelper.GetValue("JWTSecret");        /// <summary>
        /// 生成Token        /// </summary>
        /// <param name="payloadJsonStr">载荷,数据JSON字符串</param>
        /// <param name="secret">秘钥</param>
        /// <returns></returns>
        public static string GetToken(string payloadJsonStr, string secret)
        {            string payloadBase64Url = payloadJsonStr.Base64UrlEncode();            string sign = $"{_headerBase64Url}.{payloadBase64Url}".ToHMACSHA256String(secret);            return $"{_headerBase64Url}.{payloadBase64Url}.{sign}";
        }        /// <summary>
        /// 获取Token中的数据        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public static JObject GetPayload(string token)
        {            return token.Split('.')[1].Base64UrlDecode().ToJObject();
        }        /// <summary>
        /// 获取Token中的数据        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="token">token</param>
        /// <returns></returns>
        public static T GetPayload<T>(string token)
        {            if (token.IsNullOrEmpty())                return default;            return token.Split('.')[1].Base64UrlDecode().ToObject<T>();
        }        /// <summary>
        /// 校验Token        /// </summary>
        /// <param name="token">token</param>
        /// <param name="secret">密钥</param>
        /// <returns></returns>
        public static bool CheckToken(string token, string secret)
        {            var items = token.Split('.');            var oldSign = items[2];            string newSign = $"{items[0]}.{items[1]}".ToHMACSHA256String(secret);            return oldSign == newSign;
        }
    }
}

复制代码

3、定义NoCheckJWTAttribute类

复制代码

namespace HyDataMiddleground.Util
{    /// <summary>
    /// 忽略JWT校验    /// </summary>
    public class NoCheckJWTAttribute : BaseActionFilterAsync
    {
    }
}

复制代码

4、使用CheckJWTAttribute

(1)定义一个BaseApiController,所有的controller都继承该类,BaseApiController类使用CheckJWTAttribute特性

复制代码

using HyDataMiddleground.Util;using Microsoft.AspNetCore.Mvc;namespace HyDataMiddleground.Admin
{    /// <summary>
    /// Mvc对外接口基控制器    /// </summary>    [CheckJWT]    public class BaseApiController : BaseController
    {
    }
}

复制代码

(2)不需要认证的,使用NoCheckJWT限制,如下:

复制代码

     /// <summary>
        /// 用户登录        /// </summary>
        /// <param name="input">LoginInputDTO实体参数</param>
        /// <returns></returns>
        [Produces("application/json")]
        [HttpPost]
        [NoCheckJWT]        public async Task<string> SubmitLogin(LoginInputDTO input)
        {            return await _userBus.SubmitLoginAsync(input);
        }

复制代码

二、使用aspnetcore提供的组件

1、安装组件

通过nugut搜索安装Microsoft.AspNetCore.Authentication.JwtBearer 

2、jwtconfig配置

复制代码

{  
  "Jwt": {    "Issuer": "Issuer",    "Audience": "Audience",    "SigningKey": "EF1DA5B4-C7FA-4240-B997-7D1701BF9BE2"
  }  
}

复制代码

3、定义jwtconfig对应的实体

复制代码

public class JwtConfig
{    public string Issuer{get;set;}  
    public string Audience{get;set;}    public string SigningKey{get;set;}  
}

复制代码

4、Startup.cs 配置

(1)ConfigureServices 中需要进行添加的信息

复制代码

#region   Token验证信息   JWT//读取JWT的配置信息var jwtconfig = Configuration.GetSection("Jwt").Get<JwtConfig>();//JWT身份认证services.AddAuthentication(option =>{
    option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(option =>{
    option.TokenValidationParameters = new TokenValidationParameters
    {
        ValidIssuer = jwtconfig.Issuer,
        ValidAudience = jwtconfig.Audience,
        ValidateIssuer = true,
        ValidateLifetime = true,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtconfig.SigningKey)),        // 缓冲过期时间,总的有效时间等于这个时间加上jwt的过期时间,如果不配置,默认是5分钟
        ClockSkew = TimeSpan.FromSeconds(5)
    };

    option.Events = new JwtBearerEvents
    {        //此处为权限验证失败后触发的事件
        OnChallenge = context =>
        {            //此处代码为终止.Net Core默认的返回类型和数据结果,这个很重要哦,必须            context.HandleResponse();            //自定义自己想要返回的数据结果,我这里要返回的是Json对象,通过引用Newtonsoft.Json库进行转换
            var payload = JsonConvert.SerializeObject(new { message = "授权未通过,Token无效", status = false, code = 401 });            //自定义返回的数据类型
            context.Response.ContentType = "application/json";            //自定义返回状态码,默认为401 我这里改成 200
            context.Response.StatusCode = StatusCodes.Status200OK;            //输出Json数据结果            context.Response.WriteAsync(payload);            return Task.FromResult(0);
         }
    };
});

services.AddOptions().Configure<JwtConfig>(Configuration.GetSection("Jwt"));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);                            
#endregion

复制代码

(2)Configure需要添加的信息

// JWT身份认证app.UseAuthentication();
app.UseAuthorization();

以上配置好了 就基本上可以使用JWT验证了,下面介绍如何生成jwt token

5、封装了一个帮助类

复制代码

    /// <summary>
    /// JWT帮助类信息    /// </summary>
    public class JwtHelper
    {        /// <summary>
        /// 颁发JWT字符串        /// </summary>
        /// <param name="tokenModel"></param>
        /// <returns></returns>
        public static string IssueJwt(Claim[] claim)
        {            // 读取对应的配置信息
            string iss = ConfigHelper.GetSectionValue("Jwt:Issuer");            string aud = ConfigHelper.GetSectionValue("Jwt:Audience");            string secret = ConfigHelper.GetSectionValue("Jwt:SigningKey");            //加密关键字
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));            //编码格式
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);            //token存储相关信息
            var token = new JwtSecurityToken(
                issuer: iss,
                audience: aud,
                claims: claim,
                notBefore: DateTime.Now,
                expires: DateTime.Now.AddSeconds(300),
                signingCredentials: creds);            var jwtHandler = new JwtSecurityTokenHandler();            //生成对应的编码信息
            var encodedJwt = jwtHandler.WriteToken(token);            return encodedJwt;
        }        /// <summary>
        /// 解析        /// </summary>
        /// <param name="jwtStr"></param>
        /// <returns></returns>
        public static List<Claim> SerializeJwt(string jwtStr)
        {            var jwtHandler = new JwtSecurityTokenHandler();
            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);            object role;            try
            {
                jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);
            }            catch (Exception e)
            {
                Console.WriteLine(e);                throw;
            }            var list = jwtToken.Claims.ToList();            return list;
        }
    }

复制代码

6、控制器层使用示例

复制代码

        /// <summary>
        /// 测试获取token信息        /// </summary>
        /// <returns></returns>        [HttpGet]        public ActionResult<string> Get()
        {           
            //参数存储的信息
            var claim = new Claim[]{            new Claim("UserName", "测试"),            new Claim("UserId", "10086")
        };            //生成证书
            var token = JwtHelper.IssueJwt(claim);            //解析证书
            var data=  JwtHelper.SerializeJwt(token);            return Ok(new { token = token, data= data });
        }        /// <summary>
        /// 在需要身份认证的方法添加[Authorize]        /// </summary>        [Authorize]
        [HttpGet("{id}")]        public ActionResult<string> Get(int id)
        {            return "value";
        }

复制代码

然后 整体就基本上结束了。虽然说这种方式没有自定义的方式代码容易读,但是也方便了好多。


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐