写点什么

从 0 到 1 搭建权限管理系统系列三 .net8 JWT 创建 Token 并使用

  • 2024-09-24
    福建
  • 本文字数:3122 字

    阅读完需:约 10 分钟

创建 Token


创建 token 的因素(条件)有很多,在该篇文章中,采用 jwt 配置和用户基本信息作为生成 token 的基本因素(读者可根据系统,自由改变生成 token 因素)。


在 JwtPlugInUnit.CS 中创建 2 个方法(JwtPlugInUnit.CS 在上一篇文章中有写到)


方法一:PropValuesType 方法


/// <summary>/// 反射获取字段/// </summary>/// <param name="obj"></param>/// <returns></returns>public static IEnumerable<(string Name, object Value, string Type)> PropValuesType(this object obj){    List<(string a, object b, string c)> result = new List<(string a, object b, string c)>();
var type = obj.GetType(); var props = type.GetProperties(); foreach (var item in props) { result.Add((item.Name, item.GetValue(obj), item.PropertyType.Name)); } return result;}
复制代码


上述方法:PropValuesType 是通过反射获取模型字段和属性。在本文章中,是为了提取登录人员信息,编写成 List<Claim>,组成生成 token 的因素之一。


方法二:BuildToken 方法


/// <summary>/// 生成Token/// </summary>/// <param name="loginResult">登陆返回信息</param>/// <returns></returns>public static LoginOutPut BuildToken(LoginInput loginResult){    LoginOutPut result = new LoginOutPut();    //获取配置    var jwtsetting = AppSettingsPlugInUnit.GetNode<JwtSettingModel>("JwtSetting");
//准备calims,记录登录信息 var calims = loginResult.PropValuesType().Select(x => new Claim(x.Name, x.Value.ToString(), x.Type)).ToList();
//创建header var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtsetting.SecurityKey)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var header = new JwtHeader(creds);
//创建payload var payload = new JwtPayload(jwtsetting.Issuer, jwtsetting.Audience, calims, DateTime.Now, DateTime.Now.AddMinutes(jwtsetting.ExpireSeconds));
//创建令牌 var token = new JwtSecurityToken(header, payload); var tokenStr = new JwtSecurityTokenHandler().WriteToken(token); result.ExpiresDate = token.ValidTo.AddHours(8).ToString(); result.Token = tokenStr; result.UserName = loginResult.UserName;
return result;}
复制代码


上述方法:BuildToken 是创建 token 的核心代码,它通过用户信息+jwt 配置信息生成 token,并返回 token、用户名、token 过期时间等信息(读者可以添加更多返回信息)。


BuildToken 中有 2 个模型,具体结构和位置如下:



创建 Model 类,用于存放系统中模型。


LoginInput 模型结构如下:


/// <summary>/// 登录输入模型/// </summary>public class LoginInput{    /// <summary>    /// 用户名    /// </summary>    public string? UserName { get; set; }
/// <summary> /// 密码 /// </summary> public string? Password { get; set; }
}
复制代码


LoginOutPut 模型结构如下:


/// <summary>   /// 登录输入模型   /// </summary>   public class LoginOutPut   {       /// <summary>       /// 用户名       /// </summary>       public string? UserName { get; set; }
/// <summary> /// 密码 /// </summary> public string? Password { get; set; }
/// <summary> /// Token /// </summary> public string? Token { get; set; }
/// <summary> /// Token过期时间 /// </summary> public string? ExpiresDate { get; set; }
}
复制代码


做完以上操作,用户就可以生成 Token,但要把 token 运用到系统中,还需做以下操作。


创建模块分组


在 ModeuleGroupEnum.cs 中创建 2 个枚举,具体如下


/// <summary> /// 模块分组 /// </summary> public enum ModeuleGroupEnum {     /// <summary>     /// 系统菜单     /// </summary>     SysMenu = 1,
/// <summary> /// 系统用户 /// </summary> SysUser = 2,
/// <summary> /// 基础 /// </summary> Base = 3, }
复制代码


新增【系统用户】、【基础】2 个枚举。


创建新控制器


创建 2 个控制器:BaseController 和 SysUserController,结构如下



创建 BaseController 基础控制器,它存在的作用,就是承担系统中需要重写方法和获取用户基本信息的桥梁。


代码如下:


/// <summary>/// 系统基础模块/// </summary>[ApiController][Route("api/[controller]/[action]")][ApiExplorerSettings(GroupName = nameof(ModeuleGroupEnum.Base))][Authorize]public class BaseController : ControllerBase{    /// <summary>    /// 获取登陆人员信息    /// </summary>    /// <returns></returns>    [HttpGet]    public LoginOutPut GetLoginUserMsg()    {        StringValues s = new StringValues();        var auth = Request.Headers.TryGetValue("Authorization", out s);        if (string.IsNullOrWhiteSpace(s))            throw new Exception("登录信息失效");        var token = new JwtSecurityTokenHandler().ReadJwtToken(s.ToString().Replace($"{JwtBearerDefaults.AuthenticationScheme} ", ""));        LoginOutPut loginResult = new()        {            UserName = token.Claims.FirstOrDefault(f => f.Type == "UserName").Value,            Password = Convert.ToString(token.Claims.FirstOrDefault(f => f.Type == "Password").Value),        };        return loginResult;
}}
复制代码


解读下该方法:通过获取 Headers 中的 Token,然后使用 jwt 反解析 token 获取在 BuildToken 方法中记录的用户基本信息。


说明:控制器上方存在[Authorize],只要有控制器继承基础控制【BaseController】,那么该控制器下的所有方法,都需要经过 jwt 验证。如果某一个接口不需要 token 验证,就在该接口上方添加 [AllowAnonymous]


创建 SysUserController 控制器,并继承 BaseController 控制器,它的作用就是承担系统用户的所有接口,具体代码如下:


/// <summary> /// 用户模块 /// </summary> [ApiController] [Route("api/[controller]/[action]")] [ApiExplorerSettings(GroupName = nameof(ModeuleGroupEnum.SysUser))] public class SysUserController : BaseController {     /// <summary>     /// 获取Token     /// </summary>     /// <param name="userName">用户名</param>     /// <param name="password">密码</param>     [HttpGet]     [AllowAnonymous]     public string GetToken(string userName, string password)     {         var loginResult = JwtPlugInUnit.BuildToken(new LoginInput { UserName = userName, Password = password });
return loginResult.Token ?? string.Empty; } }
复制代码


可以看到,该控制器下有 2 个接口,一个为获取 token 接口(可同时作为登录接口),一个为获取登录人员信息的接口(继承 BaseController 下的 GetLoginUserMsg()方法)。


做完以上操作,jwt 中 token 验证就完成啦,看一下成果。


不使用 token 访问接口,不会成功



先获取 token



在添加使用 token



点击 Authorize 确定使用


再次访问 GetLoginUserMsg()接口,看下效果



文章转载自:陈逸子风

原文链接:https://www.cnblogs.com/cyzf/p/18422784

体验地址:http://www.jnpfsoft.com/?from=infoq


用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
从0到1搭建权限管理系统系列三 .net8 JWT创建Token并使用_Java_不在线第一只蜗牛_InfoQ写作社区