例如
使用list<apipermission>
存储角色的授权 api 列表。
可有可无。
可以把授权访问的 api 存放到 token 中,token 也可以只存放角色信息和用户身份信息。
/// <summary> /// api /// </summary> public class apipermission { /// <summary> /// api名称 /// </summary> public virtual string name { get; t; } /// <summary> /// api地址 /// </summary> public virtual string url { 会考准考证号查询get; t; } }
iauthorizationrequirement
接口代表了用户的身份信息,作为认证校验、授权校验使用。
事实上,iauthorizationrequirement
没有任何要实现的内容。
namespace microsoft.aspnetcore.authorization{ // // 摘要: // reprents an authorization requirement. public interface iauthorizationrequirement { }}
实现iauthorizationrequirement
,可以任意定义需要的属性,这些会作为自定义验证的便利手段。
要看如何使用,可以定义为全局标识,设置全局通用的数据。
我后面发现我这种写法不太好:
//iauthorizationrequirement 是 microsoft.aspnetcore.authorization 接口 /// <summary> /// 用户认证信息必要参数类 /// </summary> public class permissionrequirement : iauthorizationrequirement { /// <summary> /// 用户所属角色 /// </summary> public role roles { get; t; } = new role(); public void trolesname(string rolename) { roles.name = rolename; } /// <summary> /// 无权限时跳转到此api /// </summary> public string deniedaction { get; t; } /// <summary> /// 认证授权类型 /// </summary> public string claimtype { internal get; t; } /// <summary> /// 未授权时跳转 /// </summary> public string loginpath { get; t; } = "/account/login"; /// <summary> /// 发行人 /// </summary> public string issuer { get; t; } /// <summary> /// 订阅人 /// </summary> public string audience { get; t; } /// <summary> /// 过期时间 /// </summary> public timespan expiration { get; t; } /// <summary> /// 颁发时间 /// </summary> public long issuedtime { get; t; } /// <summary> /// 签名验证 /// </summary> public signingcredentials signingcredentials { get; t; } /// <summary> /// 构造 /// </s班级活动记录ummary> /// <param name="deniedaction">无权限时跳转到此api</param> /// <param name="urpermissions">用户权限集合</param> /// <param name="deniedaction">拒约请求的url</param> /// <param name="permissions">权限集合</param> /// <param name="claimtype">声明类型</param> /// <param name="issuer">发行人</param> /// <param name="audience">订阅人</param> /// <param name="issudtime">颁发时间</param> /// <param name="signingcredentials">签名验证实体</param> public permissionrequirement(string deniedaction, role role, string claimtype, string issuer, string audience, signingcredentials signingcredentials,long issudtime, timespan expiration) { claimtype = claimtype; deniedaction = deniedaction; roles = role; issuer = issuer; audience = audience; expiration = expiration; issuedtime = issudtime; signingcredentials = signingcredentials; } }
token 的信息配置
public static tokenvalidationparameters gettokenvalidationparameters() { var tokenvalida = new tokenvalidationparameters { // 定义 token 内容 validateissuersigningkey = true, issuersigningkey = new symmetriccuritykey(encoding.utf8.getbytes(authconfig.curitykey)), validateissuer = true, validissuer = authconfig.issuer, validateaudience = true, validaudience = authconfig.audience, validatelifetime = true, clockskew = timespan.zero, requireexpirationtime = true }; return tokenvalida; }
用于将用户的身份信息(claims)和角色授权信息(permissionrequirement)存放到 token 中。
/// <summary> /// 获取基于jwt的token /// </summary> /// <param name="urname"></param> /// <returns></returns> public static dynamic buildjwttoken(claim[] claims, permissionrequirement permissionrequirement) { var now = datetime.utcnow; var jwt = new jwtcuritytoken( issuer: permissionrequirement.issuer, audience: permissionrequirement.audience, claims: claims, notbefore: now, expires: now.add(permissionrequirement.expiration), signingcredentials: permissionrequirement.signingcredentials ); var encodedjwt = new jwtcuritytokenhandler().writetoken(jwt); var respon = new { status = true, access_token = encodedjwt, expires_in = permissionrequirement.expiration.totalmilliconds, token_type = "bearer" }; return respon; }
从别的变量导入配置信息,可有可无
// 设置用于加密 token 的密钥 // 配置角色权限 var rolerequirement = rolepermission.getrolerequirement(accounthash.gettokencuritykey()); // 定义如何生成用户的 token var tokenvalidationparameters = rolepermission.gettokenvalidationparameters();
配置 asp.net core 的身份认证服务
需要实现三个配置
addauthorization 导入角色身份认证策略addauthentication 身份认证类型addjwtbearer jwt 认证配置// 导入角色身份认证策略 rvices.addauthorization(options => { options.addpolicy("permission", policy => policy.requirements.add(rolerequirement)); // ↓ 身份认证类型 }).addauthentication(options => { options.defaultauthenticatescheme = jwtbearerdefaults.authenticationscheme; options.defaultscheme = jwtbearerdefaults.authenticationscheme; options.defaultchallengescheme = jwtbearerdefaults.authenticationscheme; // ↓ jwt 认证配置 }) .addjwtbearer(options => { options.tokenvalidationparameters = tokenvalidationparameters; options.savetoken = true; options.events = new jwtbearerevents() { // 在安全令牌通过验证和claimsidentity通过验证之后调用 // 如果用户访问注销页面 ontokenvalidated = context => { if (context.request.path.value.tostring() == "/account/logout") { var token = ((context as tokenvalidatedcontext).curitytoken as jwtcuritytoken).rawdata; } return task.completedtask; } }; });
注入自定义的授权服务 permissionhandler
注入自定义认证模型类 rolerequirement
// 添加 httpcontext 拦截 rvices.addsingleton<iauthorizationhandler, permissionhandler>(); rvices.addsingleton(rolerequirement);
添加中间件
在微软官网看到例子是这样的。。。但是我测试发现,客户端携带了 token 信息,请求通过验证上下文,还是失败,这样使用会返回403。
app.uauthentication(); app.uauthorization();
发现这样才ok:
app.uauthorization(); app.uauthentication();
可以在颁发 token 时把能够使用的 api 存储进去,但是这种方法不适合 api 较多的情况。
可以存放 用户信息(claims)和角色信息,后台通过角色信息获取授权访问的 api 列表。
/// <summary> /// 登陆 /// </summary> /// <param name="urname">用户名</param> /// <param name="password">密码</param> /// <returns>token信息</returns> [httppost("login")] pu200字日记大全blic jsonresult login(string urname, string password) { var ur = urmodel.urs.firstordefault(x => x.urname == urname && x.urpossword == password); if (ur == null) return new jsonresult( new responmodel { code = 0, message = "登陆失败!" }); // 配置用户标识 var urclaims = new claim[] { new claim(claimtypes.name,ur.urname), new claim(claimtypes.role,ur.role), new claim(claimtypes.expiration,datetime.now.addminutes(_requirement.expiration.totalminutes).tostring()), }; _requirement.trolesname(ur.role); // 生成用户标识 var identity = new claimsidentity(jwtbearerdefaults.authenticationscheme); identity.addclaims(urclaims); var token = jwttoken.buildjwttoken(urclaims, _requirement); return new jsonresult( new responmodel { code = 200, message = "登陆成功!请注意保存你的 token 凭证!", data = token }); }
[authorize(policy = "permission")]
要实现自定义 api 角色/策略授权,需要继承authorizationhandler<trequirement>
。
里面的内容是完全自定义的,authorizationhandlercontext
是认证授权的上下文,在此实现自定义的访问授权认证。
也可以加上自动刷新 token 的功能。
/// <summary> /// 验证用户信息,进行权限授权handler /// </summary> public class permissionhandler : authorizationhandler<permissionrequirement> { protected override task handlerequirementasync(authorizationhandlercontext context, permissionrequirement requirement) { list<permissionrequirement> requirements = new list<permissionrequirement>(); foreach (var item in context.requirements) { requirements.add((permissionrequirement)item); } foreach (var item in requirements) { // 校验 颁发和接收对象 if (!(ite0有绝对值吗m.issuer == authconfig.issuer ? item.audience == authconfig.audience ? true : fal : fal)) { context.fail(); } // 校验过期时间 var nowtime = datetimeofft.now.tounixtimeconds(); var issued = item.issuedtime +convert.toint64(item.expiration.totalconds); if (issued < nowtime) context.fail(); // 是否有访问此 api 的权限 var resource = ((microsoft.aspnetcore.routing.routeendpoint)context.resource).routepattern; var permissions = item.roles.permissions.tolist(); var apis = permissions.any(x => x.name.tolower() == item.roles.name.tolower() && x.url.tolower() == resource.rawtext.tolower()); if (!apis) context.fail(); context.succeed(requirement); // 无权限时跳转到某个页面 //var httpcontext = new httpcontextaccessor(); //httpcontext.httpcontext.respon.redirect(item.deniedaction); } context.succeed(requirement); return task.completedtask; } }
将字符串生成哈希值,例如密码。
为了安全,删除字符串里面的特殊字符,例如"
、'
、$
。
public static class accounthash { // 获取字符串的哈希值 public static string getbyhashstring(string str) { string hash = getmd5hash(str.replace("\"", string.empty) .replace("\'", string.empty) .replace("$", string.empty)); return hash; } /// <summary> /// 获取用于加密 token 的密钥 /// </summary> /// <returns></returns> public static signingcredentials gettokencuritykey() { var curitykey = new signingcredentials( new symmetriccuritykey( encoding.utf8.getbytes(authconfig.curitykey)), curityalgorithms.hmacsha256); return curitykey; } private static string getmd5hash(string source) { md5 md5hash = md5.create(); byte[] data = md5hash.computehash(encoding.utf8.getbytes(source)); stringbuilder sbuilder = new stringbuilder(); for (int i = 0; i < data.length; i++) { sbuilder.append(data[i].tostring("x2")); } return sbuilder.tostring(); } }
签发 token
permissionrequirement
不是必须的,用来存放角色或策略认证信息,claims 应该是必须的。
/// <summary> /// 颁发用户token /// </summary> public class jwttoken { /// <summary> /// 获取基于jwt的token /// </summary> /// <param name="urname"></param> /// <returns></returns> public static dynamic buildjwttoken(claim[] claims, permissionrequirement permissionrequirement) { var now = datetime.utcnow; var jwt = new jwtcuritytoken( issuer: permissionrequirement.issuer, audience: permissionrequirement.audience, claims: claims, notbefore: now, expires: now.add(permissionrequirement.expiration), signingcredentials: permissionrequirement.signingcredentials ); var encodedjwt = new jwtcuritytokenhandler().writetoken(jwt); var respon = new { st钞票的英文atus = true, access_token = encodedjwt, expires_in = permissionrequirement.expiration.totalmilliconds, token_type = "bearer" }; return respon; }
表示时间戳
// unix 时间戳datetimeofft.now.tounixtimeconds();// 检验 token 是否过期// 将 timespan 转为 unix 时间戳convert.toint64(timespan);datetimeofft.now.tounixtimeconds() + convert.toint64(timespan);
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持www.887551.com。
本文发布于:2023-04-04 15:44:13,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/fc046178448f7a2316e27819954f1f58.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:ASP.NET Core使用JWT自定义角色并实现策略授权需要的接口.doc
本文 PDF 下载地址:ASP.NET Core使用JWT自定义角色并实现策略授权需要的接口.pdf
留言与评论(共有 0 条评论) |