ASP.NET Core JWT授权验证----自定义处理类
- JWT IAuthorizationRequirement一、 JWT配置 配置文件添加节点
"Audience": {
"Secret": "sdfsdfsrty45634kkhllghtdgdfss345t678fs", //不要太短,16位+
"SecretFile": "C:\\my-file\\blog.core.audience.secret.txt", //安全。内容就是Secret
"Issuer": "Blog.Core",
"Audience": "wr"
}二、新增 类 PermissionRequirement 继承 IAuthorizationRequirement,用于设计自定义权限处理器PermissionHandler
public class PermissionRequirement : IAuthorizationRequirement
{
/// <summary>
/// 用户权限集合,一个订单包含了很多详情,
/// 同理,一个网站的认证发行中,也有很多权限详情(这里是Role和URL的关系)
/// </summary>
public List<PermissionItem> Permissions { get; set; }
/// <summary>
/// 无权限action
/// </summary>
public string DeniedAction { get; set; }
/// <summary>
/// 认证授权类型
/// </summary>
public string ClaimType { internal get; set; }
/// <summary>
/// 请求路径
/// </summary>
public string LoginPath { get; set; } = "/Api/Login";
/// <summary>
/// 发行人
/// </summary>
public string Issuer { get; set; }
/// <summary>
/// 订阅人
/// </summary>
public string Audience { get; set; }
/// <summary>
/// 过期时间
/// </summary>
public TimeSpan Expiration { get; set; }
/// <summary>
/// 签名验证
/// </summary>
public SigningCredentials SigningCredentials { get; set; }
/// <summary>
/// 构造
/// </summary>
/// <param name="deniedAction">拒约请求的url</param>
/// <param name="permissions">权限集合</param>
/// <param name="claimType">声明类型</param>
/// <param name="issuer">发行人</param>
/// <param name="audience">订阅人</param>
/// <param name="signingCredentials">签名验证实体</param>
/// <param name="expiration">过期时间</param>
public PermissionRequirement(string deniedAction, List<PermissionItem> permissions, string claimType, string issuer, string audience, SigningCredentials signingCredentials, TimeSpan expiration)
{
ClaimType = claimType;
DeniedAction = deniedAction;
Permissions = permissions;
Issuer = issuer;
Audience = audience;
Expiration = expiration;
SigningCredentials = signingCredentials;
}
}
/// <summary>
/// 用户或角色或其他凭据实体,就像是订单详情一样
/// 之前的名字是 Permission
/// </summary>
public class PermissionItem
{
/// <summary>
/// 用户或角色或其他凭据名称
/// </summary>
public virtual string Role { get; set; }
/// <summary>
/// 请求Url
/// </summary>
public virtual string Url { get; set; }
}三、增加自定义处理类PermissionHandler
public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
{
/// <summary>
/// 验证方案提供对象
/// </summary>
public IAuthenticationSchemeProvider Schemes { get; set; }
private readonly IHttpContextAccessor _accessor;
private readonly IUser _user;
/// <summary>
/// 构造函数注入
/// </summary>
/// <param name="schemes"></param>
/// <param name="roleModulePermissionServices"></param>
/// <param name="accessor"></param>
/// <param name="userServices"></param>
/// <param name="user"></param>
public PermissionHandler(IAuthenticationSchemeProvider schemes,
IHttpContextAccessor accessor,
IUser user)
{
_accessor = accessor;
_user = user;
Schemes = schemes;
}
// 重写异步处理程序 当基于策略授权时触发 [Authorize("Permission")]
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
PermissionRequirement requirement)
{
var httpContext = _accessor.HttpContext;
//验证用户角色 权限等
}
}四、 定义和注册上面的用到的服务 IHttpContextAccessor 、IUser
// 注册以后可以访问上线问 HttpContext 利用ASP.NET Core提供的IHttpContextAccessor来获取HttpContext的User属性 services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//注入NetUser用户接口 HttpContext services.AddScoped<IUser, AspNetUser>();
// 注入自定义权限处理器 用于策略授权验证 services.AddScoped<IAuthorizationHandler, PermissionHandler>();
五、定义上面的类 AspNetUser
public class AspNetUser : IUser
{
private readonly IHttpContextAccessor _accessor;
private readonly ILogger<AspNetUser> _logger;
public AspNetUser(IHttpContextAccessor accessor, ILogger<AspNetUser> logger)
{
_accessor = accessor;
_logger = logger;
}
public string Name => GetName();
private string GetName()
{
if (IsAuthenticated() && (_accessor.HttpContext?.User.Identity?.Name??"").IsNotEmptyOrNull())
{
return _accessor.HttpContext.User.Identity.Name??"";
}
else
{
if (!string.IsNullOrEmpty(GetToken()))
{
var getNameType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name";
return GetUserInfoFromToken(getNameType).FirstOrDefault().ObjToString();
}
}
return "";
}
public long ID => GetClaimValueByType("jti").FirstOrDefault().ObjToLong();
public long TenantId => GetClaimValueByType("TenantId").FirstOrDefault().ObjToLong();
public bool IsAuthenticated()
{
return _accessor.HttpContext?.User?.Identity?.IsAuthenticated ?? false;
}
public string GetToken()
{
var token = _accessor.HttpContext?.Request?.Headers["Authorization"].ObjToString().Replace("Bearer ", "");
if (!token.IsNullOrEmpty())
{
return token;
}
if (_accessor.HttpContext?.IsSuccessSwagger() == true)
{
token = _accessor.HttpContext.GetSuccessSwaggerJwt();
if (token.IsNotEmptyOrNull())
{
if (_accessor.HttpContext.User.Claims.Any(s => s.Type == JwtRegisteredClaimNames.Jti))
{
return token;
}
var claims = new ClaimsIdentity(GetClaimsIdentity(token));
_accessor.HttpContext.User.AddIdentity(claims);
return token;
}
}
return token;
}
}六 、定义封装策略配置
public static void AddAuthorizationSetup(this IServiceCollection services)
{
if (services == null) throw new ArgumentNullException(nameof(services));
#region 参数
//读取配置文件
var symmetricKeyAsBase64 = AppSettings.app(new string[] { "Audience", "Secret" });
var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
var signingKey = new SymmetricSecurityKey(keyByteArray);
var Issuer = AppSettings.app(new string[] { "Audience", "Issuer" });
var Audience = AppSettings.app(new string[] { "Audience", "Audience" });
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
// 如果要数据库动态绑定,这里先留个空,后边处理器里动态赋值
var permission = new List<PermissionItem>();
// 角色与接口的权限要求参数
var permissionRequirement = new PermissionRequirement(
"/api/denied",// 拒绝授权的跳转地址(目前无用)
permission,
ClaimTypes.Role,//基于角色的授权
Issuer,//发行人
Audience,//听众
signingCredentials,//签名凭据
expiration: TimeSpan.FromSeconds(60 * 60)//接口的过期时间
);
#endregion
// 3、自定义复杂的策略授权
services.AddAuthorization(options =>
{
options.AddPolicy("Permissions",
policy => policy.Requirements.Add(permissionRequirement));
});
services.AddSingleton(permissionRequirement);
}七、调用策略配置 Program.cs
builder.Services.AddAuthorizationSetup();