.net core 使用jwt验证
1.在.net core项目中的Startup文件中添加配置
//public void ConfigureServices(IServiceCollection services)
services.AddAuthorizationSetupForClient();
//public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseJwtTokenAuthMildd();
2.AddAuthorizationSetupForClient方法实现
using CJSite_Utils.Auth.Policys;
using CJSite_Utils.Configuration;
using CJSite_Utils.Utility.Extensions;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace CJSite_Utils.Auth
{
/// <summary>
/// Db 启动服务
/// </summary>
public static class AuthorizationSetup
{
/// <summary>
/// 用户jwt初始化设置
/// </summary>
/// <param name="services"></param>
public static void AddAuthorizationSetupForClient(this IServiceCollection services)
{
if (services == null) throw new ArgumentNullException(nameof(services));
#region 参数
//读取配置文件
var symmetricKeyAsBase64 = AppSettingsConstVars.JwtConfigSecretKey;
var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
var signingKey = new SymmetricSecurityKey(keyByteArray);
var issuer = AppSettingsConstVars.JwtConfigIssuer;
var audience = AppSettingsConstVars.JwtConfigAudience;
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
// 如果要数据库动态绑定,这里先留个空,后边处理器里动态赋值
var permission = new List<PermissionItem>();
permission.Add(new PermissionItem()
{
RoleData = ClaimTypes.UserData,//基于角色的授权
Role = ClaimTypes.Sid,//用户最大权限值
});
// 角色与接口的权限要求参数
var permissionRequirement = new PermissionRequirement(
"/api/denied",// 拒绝授权的跳转地址(目前无用)
permission,
//ClaimTypes.Role,//基于角色的授权
ClaimTypes.UserData,//基于登录用户数据授权
issuer,//发行人
audience,//听众
signingCredentials,//签名凭据
expiration: TimeSpan.FromSeconds(60 * 60 * 24)//接口的过期时间
);
#endregion
// 复杂的策略授权
services.AddAuthorization(options =>
{
options.AddPolicy(Permissions.Name, policy => policy.Requirements.Add(permissionRequirement));
});
// 令牌验证参数
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true, //是否验证SecurityKey
IssuerSigningKey = signingKey, //拿到SecurityKey
ValidateIssuer = true, //是否验证Issuer
ValidIssuer = issuer,//发行人
ValidateAudience = true, //是否验证Audience
ValidAudience = audience,//订阅人
ValidateLifetime = true, //是否验证失效时间
ClockSkew = TimeSpan.FromSeconds(60),
RequireExpirationTime = true,
};
// core自带官方JWT认证,开启Bearer认证
services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = nameof(ApiResponseForClientHandler);
o.DefaultForbidScheme = nameof(ApiResponseForClientHandler);
})
// 添加JwtBearer服务
.AddJwtBearer(o =>
{
o.TokenValidationParameters = tokenValidationParameters;
o.Events = new JwtBearerEvents
{
OnChallenge = context =>
{
context.Response.Headers.Add("Token-Error", context.ErrorDescription);
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
var token = context.Request.Headers["Authorization"].ObjectToString().Replace("Bearer ", "");
var jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token);
if (jwtToken.Issuer != issuer)
{
context.Response.Headers.Add("Token-Error-Iss", "issuer is wrong!");
}
if (jwtToken.Audiences.FirstOrDefault() != audience)
{
context.Response.Headers.Add("Token-Error-Aud", "Audience is wrong!");
}
// 如果过期,则把<是否过期>添加到,返回头信息中
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("Token-Expired", "true");
}
return Task.CompletedTask;
}
};
})
.AddScheme<AuthenticationSchemeOptions, ApiResponseForClientHandler>(nameof(ApiResponseForClientHandler), o => { });
// 注入权限处理器
services.AddScoped<IAuthorizationHandler, PermissionForClientHandler>();
services.AddSingleton(permissionRequirement);
}
}
}
PermissionRequirement
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
namespace CJSite_Utils.Auth.Policys
{
/// <summary>
/// 必要参数类
/// 继承 IAuthorizationRequirement,用于设计自定义权限处理器PermissionHandler
/// 因为AuthorizationHandler 中的泛型参数 TRequirement 必须继承 IAuthorizationRequirement
/// </summary>
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; }
//public string UserId { 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;
}
}
}
PermissionItem
using System;
using System.Collections.Generic;
using System.Text;
namespace CJSite_Utils.Auth.Policys
{
/// <summary>
/// 用户或角色或其他凭据实体
/// </summary>
public class PermissionItem
{
/// <summary>
/// 用户或角色或其他凭据名称
/// </summary>
public virtual string Role { get; set; }
public virtual string RoleData { get; set; }
/// <summary>
/// 请求Url
/// </summary>
public virtual string Url { get; set; }
/// <summary>
/// 权限标识
/// </summary>
public virtual string Authority { get; set; }
/// <summary>
/// 路由标识Url
/// </summary>
public virtual string RouteUrl { get; set; }
}
}
ApiResponseForClientHandler
using CJSite_Utils.Utility.Model;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
namespace CJSite_Utils.Auth.Policys
{
public class ApiResponseForClientHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public ApiResponseForClientHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
throw new NotImplementedException();
}
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
{
Response.ContentType = "application/json";
//Response.StatusCode = StatusCodes.Status401Unauthorized;
//await Response.WriteAsync(JsonConvert.SerializeObject(new ApiResponse(StatusCode.CODE401)));
var res = new ResponseModel<int>(ResponseModelType.Unauthorized, "很抱歉,授权失效,请重新登录!");
await Response.WriteAsync(JsonConvert.SerializeObject(res));
}
protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
{
Response.ContentType = "application/json";
//Response.StatusCode = StatusCodes.Status403Forbidden;
//await Response.WriteAsync(JsonConvert.SerializeObject(new ApiResponse(StatusCode.CODE403)));
var res = new ResponseModel<int>(ResponseModelType.Unauthorized, "很抱歉,授权失效,请重新登录!");
await Response.WriteAsync(JsonConvert.SerializeObject(res));
}
}
}
PermissionForClientHandler
using CJSite_Utils.Configuration;
using CJSite_Utils.Utility.AutoFac;
using CJSite_Utils.Utility.Extensions;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using System.Data;
using CJSite_Utils.Utility.Model;
namespace CJSite_Utils.Auth.Policys
{
/// <summary>
/// 权限授权处理器
/// </summary>
public class PermissionForClientHandler : AuthorizationHandler<PermissionRequirement>
{
/// <summary>
/// 验证方案提供对象
/// </summary>
public IAuthenticationSchemeProvider Schemes { get; set; }
private readonly IHttpContextAccessor _accessor;
public readonly DbConnection con;
/// <summary>
/// redis中的缓存值
/// </summary>
//private RedisHash redisHash { get; set; }
/// <summary>
/// 存储缓存数据
/// </summary>
private PermissionRedis<string> permission { get; set; }
private readonly ResponseModel<List<string>> res = new ResponseModel<List<string>>(ResponseModelType.Noauthorized, null, "很抱歉,您的访问权限等级不够,联系管理员!");
private readonly ResponseModel<List<string>> resNoInfo = new ResponseModel<List<string>>(ResponseModelType.Noauthorized_NoInfo, null, "很抱歉,您的访问权限等级不够,联系管理员!");
/// <summary>
/// 构造函数注入
/// </summary>
/// <param name="schemes"></param>
/// <param name="navigationRepository"></param>
/// <param name="accessor"></param>
public PermissionForClientHandler(IAuthenticationSchemeProvider schemes, IHttpContextAccessor accessor)
{
_accessor = accessor;
Schemes = schemes;
//con = AutofacUtil.GetService<DbContext>().Database.GetDbConnection();
}
// 重写异步处理程序
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
var httpContext = _accessor.HttpContext;
if (AppSettingsConstVars.IsDev || httpContext.Request.Path.Value.Contains("User/Login") || httpContext.Request.Path.Value.Contains("User/GetToken"))
{
context.Succeed(requirement);
return;
}
if (!requirement.Permissions.Any())
{
}
//请求Url
if (httpContext != null)
{
var questUrl = httpContext.Request.Path.Value.ToLower();
//判断请求是否停止
var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
{
if (await handlers.GetHandlerAsync(httpContext, scheme.Name) is IAuthenticationRequestHandler handler && await handler.HandleRequestAsync())
{
context.Fail();
return;
}
}
//判断请求是否拥有凭据,即有没有登录
var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
if (defaultAuthenticate != null)
{
var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name);
//result?.Principal不为空即登录成功
if (result?.Principal != null)
{
httpContext.User = result.Principal;
//判断过期时间(这里仅仅是最坏验证原则,你可以不要这个if else的判断,因为我们使用的官方验证,Token过期后上边的result?.Principal 就为 null 了,进不到这里了,因此这里其实可以不用验证过期时间,只是做最后严谨判断)
if (!((httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) != null && DateTime.Parse(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) >= DateTime.Now))
{
context.Fail();
return;
}
//权限中是否存在请求的url
if (!AppSettingsConstVars.IsDev)
{
// 获取当前用户的角色信息
var currentUserRoles = (from item in httpContext.User.Claims
where item.Type == requirement.ClaimType
select item.Value).ToList();
//获取当前角色的权限值
var userClassRole = (from item in httpContext.User.Claims
where item.Type == requirement.Permissions.FirstOrDefault().Role
select item.Value).FirstOrDefault();
}
}
else
{
context.Fail();
return;
}
}
else
{
context.Fail();
return;
}
//判断没有登录时,是否访问登录的url,并且是Post请求,并且是form表单提交类型,否则为失败
//if (!questUrl.Equals(requirement.LoginPath.ToLower(), StringComparison.Ordinal) && (!httpContext.Request.Method.Equals("POST") || !httpContext.Request.HasJsonContentType()))
//{
// context.Fail();
// return;
//}
}
context.Succeed(requirement);
}
private PermissionRedis<string> RedisUpdatePerminnName()
{
PermissionRedis<string> redis = new PermissionRedis<string>();
redis.Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
//redis.Permissions = con.Query<string>(" select [id] from [dbo].[CJSite_Role] where [Class]>=@cl", new { cl = GlobalConstVars.RoleMaxClass }).ToList();
//redisHash.HashSet(AppSettingsConstVars.SystemName "rs", GlobalConstVars.RolesName, redis);
return redis;
}
}
}
3.最后在需要添加验证的方法上添加下面标签即可
[Authorize(Permissions.Name)]
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhiaeckc
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
微信运动停用后别人还能看到步数吗
PHP中文网 07-22 -
excel打印预览压线压字怎么办
PHP中文网 06-22