首先添加Nuget包
1.在CommonCode项目中建立 JWTHelper
IJwtModel.cs
namespace CommonCode.JWT //注意命名空间和文件夹名不一致
{
internal class IJwtModel
{
public string Issuer { get; set; }
public string Audience { get; set; }
public double Expires { get; set; }
}
}
JwtModel.cs
namespace CommonCode.JWT //注意命名空间和文件夹名不一致
{
internal class JwtModel: IJwtModel
{
public string Issuer { get; set; }
public string Audience { get; set; }
public double Expires { get; set; }
}
}
JwtHelper.cs
using CommonCode.Converts;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using System.Security.Claims;
namespace CommonCode.JWT
{
/// <summary>
/// 单例
/// 用于产生Token和验证Token
/// </summary>
public class JwtHelper
{
private readonly static JwtSecurityTokenHandler _jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
/// <summary>
/// 创建加密JwtToken
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public static string CreateJwtToken<T, U>(in T user,in U jwt, SymmetricSecurityKey secretKey)
{
IJwtModel jwtModel = ConvertTo.ConvertModel<U,JwtModel>(jwt);
var claimList = CreateClaimList<T>(user);
// 选择加密算法
var algorithm = SecurityAlgorithms.HmacSha256;
// 生成Credentials
var signingCredentials = new SigningCredentials(secretKey, algorithm);
JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(
jwtModel.Issuer, //Issuer
jwtModel.Audience, //Audience
claims: claimList,
DateTime.Now, //notBefore
DateTime.Now.AddDays(jwtModel.Expires), //expires
signingCredentials //Credentials
);
string jwtToken = _jwtSecurityTokenHandler.WriteToken(jwtSecurityToken);
return jwtToken;
}
public static T GetToken<T>(string Token)
{
Type t = typeof(T);
object objA = Activator.CreateInstance(t);
var b = _jwtSecurityTokenHandler.ReadJwtToken(Token);
foreach (var item in b.Claims)
{
PropertyInfo _Property = t.GetProperty(item.Type);
if (_Property != null && _Property.CanRead)
{
_Property.SetValue(objA, item.Value, null);
}
}
return (T)objA;
}
/// <summary>
/// 创建包含用户信息的CalimList
/// </summary>
/// <param name="authUser"></param>
/// <returns></returns>
private static List<Claim> CreateClaimList<T>(T authUser)
{
var Class = typeof(T);
List<Claim> claimList = new List<Claim>();
foreach (var item in Class.GetProperties())
{
claimList.Add(new Claim(item.Name, Convert.ToString(item.GetValue(authUser))));
}
return claimList;
}
}
}
这里用到了一个类转换的工具,需要建立一下
ConverTo.cs
using System.Reflection;
namespace CommonCode.Converts
{
public class ConvertTo
{
/// <summary>
/// 实体类转换,要求两个类中的成员一致 ///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="P"></typeparam>
/// <param name="pModel"></param>
/// <returns></returns>
public static T ConvertModel<P,T>(in P pModel)
{
T ret = System.Activator.CreateInstance<T>();
List<PropertyInfo> p_pis = pModel.GetType().GetProperties().ToList();
PropertyInfo[] t_pis = typeof(T).GetProperties();
foreach (PropertyInfo pi in t_pis)
{
//可写入数据
if (pi.CanWrite)
{
//忽略大小写
var name = p_pis.Find(s => s.Name.ToLower() == pi.Name.ToLower());
if (name != null && pi.PropertyType.Name == name.PropertyType.Name)
{
pi.SetValue(ret, name.GetValue(pModel, null), null);
}
}
}
return ret;
}
}
}
2。然后在Utility项目中建立TokenHelper
在编写TokenHelper之前 ,我们需要在IRepository和Repository中建立 TokenModel,以实现依赖注入
创建ITokenModel
ITokenModel.cs
namespace NET6Demo.IRepository //注意命名空间,不带文件夹名称
{
public interface ITokenModel
{
string Issuer { get; set; }
string Audience { get; set; }
double Expires { get; set; }
}
}
创建TokenModel
TokenModel.cs
namespace NET6Demo.Repository
{
public class TokenModel : ITokenModel, IDependency
{
public string Issuer { get; set; }
public string Audience { get; set; }
public double Expires { get; set; }
}
}
创建TokenHelper
TokenHelper.cs
using NET6Demo.IRepository;
using CommonCode.JWT;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
namespace NET6Demo.Utility.Token
{
public class TokenHelper
{
private readonly IConfiguration _configuration;
private readonly JwtSecurityTokenHandler _jwtSecurityTokenHandler;
private readonly ILogger<TokenHelper> _logger;
private ITokenModel _tokenModel;
private IUserInfo _user;
public TokenHelper(
IConfiguration configuration,
JwtSecurityTokenHandler jwtSecurityTokenHandler,
ILogger<TokenHelper> logger,
ITokenModel tokenModel
IUserInfo user
)
{
_configuration = configuration;
_jwtSecurityTokenHandler = jwtSecurityTokenHandler;
_logger = logger;
_tokenModel = tokenModel;
_user = user;
}
// <summary>
/// 创建加密JwtToken
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public string CreateJwtToken()
{
//_user = user;
// 从 appsettings.json 中读取配置
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:SecretKey"]));
_tokenModel.Expires = Convert.ToDouble(_configuration["JWT:Expires"]);
_tokenModel.Issuer = _configuration["JWT:Issuer"];
_tokenModel.Audience = _configuration["JWT:Audience"];
return JwtHelper.CreateJwtToken(_user, _tokenModel, secretKey);
}
public IUserInfo GetToken(string Token)
{
return JwtHelper.GetToken<IUserInfo>(Token);
}
public bool VerTokenAsync(string Token)
{
//业务逻辑暂时没有写
return true;
}
}
}
在Utility项目中的Autofac中,添加对TokenHelper的注册
之前代码里其实已经有了这一句,只要去掉注释就好啦
// 用于Jwt的各种操作
container.RegisterType<JwtSecurityTokenHandler>().InstancePerLifetimeScope();
//自己写的支持泛型存入Jwt 便于扩展
container.RegisterType<TokenHelper>().InstancePerLifetimeScope();
在appsetting.json中添加jwt的参数
"JWT": {
"Issuer": "com.xxx.authService",
"Audience": "oauth/com.xxx.authService",
"SecretKey": "neAuTkkQv1xgXVyr",
"Expires": "3"
}
3.开启Authorization
在Utility项目中创建Net6DemoAuthorizationMiddleware.
注意:这里需要给项目添加一个Nuget包,这个包不知道为什么自己认不上,需要手动安装
Net6DemoAuthorizationMiddleware.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;
namespace NET6Demo.Utility.Authorize
{
public class Net6DemoAuthorizationMiddleware : IAuthorizationMiddlewareResultHandler
{
private readonly AuthorizationMiddlewareResultHandler defaultHandler = new();
public async Task HandleAsync(
RequestDelegate next,
HttpContext context,
AuthorizationPolicy policy,
PolicyAuthorizationResult authorizeResult)
{
if (authorizeResult.Forbidden
&& authorizeResult.AuthorizationFailure!.FailedRequirements
.OfType<Show404Requirement>().Any())
{
// Return a 404 to make it appear as if the resource doesn't exist.
throw new KeyNotFoundException();
}
throw new ApplicationException("Invalid token");
}
}
public class Show404Requirement : IAuthorizationRequirement { }
}
在program.cs中添加
#region 添加身份验证JWT
builder.Services.AddSingleton<
IAuthorizationMiddlewareResultHandler, Net6DemoAuthorizationMiddleware>();
//添加jwt验证:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidIssuer = builder.Configuration["JWT:Issuer"],
ValidateAudience = true,
ValidAudience = builder.Configuration["JWT:Audience"],
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:SecretKey"]))
};
});
#endregion
#region 启用身份验证
//下面的app添加这个 和这个长得很像 app.UseAuthorization();
app.UseAuthentication();//在前
app.UseAuthorization();//在后
#endregion
现在修改TestController,添加JwtSecurityTokenHandler,TokenHelper的依赖注入
public class TestController : BaseController
{
private ILogger<TestController> _logger;
private readonly IServiceProvider _provider;
private IUserInfo _user;
private JwtSecurityTokenHandler _jwtHandler;
private TokenHelper _tokenHelper;
public TestController(
ILogger<TestController> logger,
IServiceProvider provider,
IUserInfo user,
JwtSecurityTokenHandler jwtSecurityTokenHandler,
TokenHelper tokenHelper)
{
_logger = logger;
_provider = provider;
_user = user;
_jwtHandler = jwtSecurityTokenHandler;
_tokenHelper = tokenHelper;
}
[AllowAnonymous]
[HttpGet("GetTest")]
public async Task<IActionResult> GetTestResult(string userId)
{
Console.WriteLine("测试一下输出日志");
_logger.LogInformation("日志输出了");
_user = _provider.GetService<IUsers>().GetUser(userId);
//throw new Exception("Test exception");
//return Ok(_user);
//return BadRequest();
return Ok(_tokenHelper.CreateJwtToken(_user));
}
}
运行项目,在swagger中得到结果
可以拿到JWT的官网去检验一下
至于解析和检验的方法,按照API中写就可以了。就不再多说
至此JWT和身份验证搭建完毕