首页 > 作文

ASP.NET Core使用JWT自定义角色并实现策略授权需要的接口

更新时间:2023-04-04 15:44:15 阅读: 评论:0

① 存储角色/用户所能访问的 api

例如

使用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接口代表了用户的身份信息,作为认证校验、授权校验使用。

事实上,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;        }    }

③ 实现 tokenvalidationparameters

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;        }

④ 生成 token

用于将用户的身份信息(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                });        }

⑦ 添加 api 授权策略

    [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 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图