一、自定义CheckJWTAttribute特性方式之前使用的是这种方式,根据jwt原理自定义生成JWT、验证jwt,感觉挺好。原理就是自定义一个拦截器(特性),拦截器对每个请求都优先进行处理,认证成功的进行下一步操作。1、定...
一、自定义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
using Newtonsoft.Json;
using System;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace HyDataMiddleground.Util
{
public static partial class Extention
{
/// <summary>
/// 构造函数
/// </summary>
static Extention()
{
JsonSerializerSettings setting = new JsonSerializerSettings();
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
setting.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
setting.DateFormatString = "yyyy-MM-dd HH:mm:ss";
return setting;
});
}
/// <summary>
/// 将对象序列化成Json字符串
/// </summary>
/// <param name="obj">需要序列化的对象</param>
/// <returns></returns>
public static string ToJson(this object obj)
{
return JsonConvert.SerializeObject(obj);
}
}
}
(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";
}
然后 整体就基本上结束了。虽然说这种方式没有自定义的方式代码容易读,但是也方便了好多。
本文标题为:NET CORE项目中JWT的使用
- WPF使用DrawingContext实现绘制刻度条 2023-07-04
- user32.dll 函数说明小结 2022-12-26
- c# 模拟线性回归的示例 2023-03-14
- Unity3D实现渐变颜色效果 2023-01-16
- C# 使用Aspose.Cells 导出Excel的步骤及问题记录 2023-05-16
- 如何使用C# 捕获进程输出 2023-03-10
- .NET CORE DI 依赖注入 2023-09-27
- Unity Shader实现模糊效果 2023-04-27
- Oracle中for循环的使用方法 2023-07-04
- 在C# 8中如何使用默认接口方法详解 2023-03-29
