创建 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
评论