返回顶部
首页 > 资讯 > 精选 >ASP.NET Core如何使用JWT自定义角色并实现策略授权需要的接口
  • 514
分享到

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

2023-06-26 06:06:14 514人浏览 安东尼
摘要

asp.net Core如何使用Jwt自定义角色并实现策略授权需要的接口,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。① 存储角色/用户所能访问的 a

asp.net Core如何使用Jwt自定义角色并实现策略授权需要的接口,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

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

例如

使用 List<ApiPermission> 存储角色的授权 API 列表。

可有可无。

可以把授权访问的 API 存放到 Token 中,Token 也可以只存放角色信息和用户身份信息。

    /// <summary>    /// API    /// </summary>    public class ApiPermission    {        /// <summary>        /// API名称        /// </summary>        public virtual string Name { get; set; }        /// <summary>        /// API地址        /// </summary>        public virtual string Url { get; set; }    }

② 实现 IAuthorizationRequirement 接口

IAuthorizationRequirement 接口代表了用户的身份信息,作为认证校验、授权校验使用。

事实上,IAuthorizationRequirement 没有任何要实现的内容。

namespace Microsoft.Aspnetcore.Authorization{    //    // 摘要:    //     Represents an authorization requirement.    public interface IAuthorizationRequirement    {    }}

实现 IAuthorizationRequirement ,可以任意定义需要的属性,这些会作为自定义验证的便利手段。
要看如何使用,可以定义为全局标识,设置全局通用的数据。
我后面发现我这种写法不太好:

    //IAuthorizationRequirement 是 Microsoft.AspNetCore.Authorization 接口    /// <summary>    /// 用户认证信息必要参数类    /// </summary>    public class PermissionRequirement : IAuthorizationRequirement    {        /// <summary>        /// 用户所属角色        /// </summary>        public Role Roles { get;  set; } = new Role();        public void SetRolesName(string roleName)        {            Roles.Name = roleName;        }        /// <summary>        /// 无权限时跳转到此API        /// </summary>        public string DeniedAction { get; set; }        /// <summary>        /// 认证授权类型        /// </summary>        public string ClaimType { internal get; set; }        /// <summary>        /// 未授权时跳转        /// </summary>        public string LoginPath { get; set; } = "/Account/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 long IssuedTime { get; set; }        /// <summary>        /// 签名验证        /// </summary>        public SigninGCredentials SigningCredentials { get; set; }        /// <summary>        /// 构造        /// </summary>        /// <param name="deniedAction">无权限时跳转到此API</param>        /// <param name="userPermissions">用户权限集合</param>        /// <param name="deniedAction">拒约请求的url</param>        /// <param name="permissions">权限集合</param>        /// <param name="claimType">声明类型</param>        /// <param name="issuer">发行人</param>        /// <param name="audience">订阅人</param>        /// <param name="issusedTime">颁发时间</param>        /// <param name="signingCredentials">签名验证实体</param>        public PermissionRequirement(string deniedAction, Role Role, string claimType, string issuer, string audience, SigningCredentials signingCredentials,long issusedTime, TimeSpan expiration)        {            ClaimType = claimType;            DeniedAction = deniedAction;            Roles = Role;            Issuer = issuer;            Audience = audience;            Expiration = expiration;            IssuedTime = issusedTime;            SigningCredentials = signingCredentials;        }    }

③ 实现 TokenValidationParameters

Token 的信息配置

        public static TokenValidationParameters GetTokenValidationParameters()        {            var tokenValida = new TokenValidationParameters            {                // 定义 Token 内容                ValidateIssuerSigningKey = true,                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AuthConfig.SecurityKey)),                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="username"></param>        /// <returns></returns>        public static dynamic BuildJwtToken(Claim[] claims, PermissionRequirement permissionRequirement)        {            var now = DateTime.UtcNow;            var jwt = new JwtSecurityToken(                issuer: permissionRequirement.Issuer,                audience: permissionRequirement.Audience,                claims: claims,                notBefore: now,                expires: now.Add(permissionRequirement.Expiration),                signingCredentials: permissionRequirement.SigningCredentials            );            var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);            var response = new            {                Status = true,                access_token = encodedJwt,                expires_in = permissionRequirement.Expiration.TotalMilliseconds,                token_type = "Bearer"            };            return response;        }

⑤ 实现服务注入和身份认证配置

从别的变量导入配置信息,可有可无

            // 设置用于加密 Token 的密钥            // 配置角色权限             var roleRequirement = RolePermission.GetRoleRequirement(AccountHash.GetTokenSecurityKey());            // 定义如何生成用户的 Token            var tokenValidationParameters = RolePermission.GetTokenValidationParameters();

配置 ASP.net core 的身份认证服务

需要实现三个配置

  • AddAuthorization 导入角色身份认证策略

  • AddAuthentication 身份认证类型

  • AddJwtBearer Jwt 认证配置

            // 导入角色身份认证策略            services.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).SecurityToken as JwtSecurityToken).RawData;                        }                        return Task.CompletedTask;                    }                };            });

注入自定义的授权服务 PermissionHandler

注入自定义认证模型类 roleRequirement

            // 添加 Httpcontext 拦截            services.AddSingleton<IAuthorizationHandler, PermissionHandler>();            services.AddSingleton(roleRequirement);

添加中间件

在微软官网看到例子是这样的。。。但是我测试发现,客户端携带了 Token 信息,请求通过验证上下文,还是失败,这样使用会返回403。

    app.UseAuthentication();    app.UseAuthorization();

发现这样才OK:

            app.UseAuthorization();            app.UseAuthentication();

⑥ 实现登陆

可以在颁发 Token 时把能够使用的 API 存储进去,但是这种方法不适合 API 较多的情况。

可以存放 用户信息(Claims)和角色信息,后台通过角色信息获取授权访问的 API 列表。

        /// <summary>        /// 登陆        /// </summary>        /// <param name="username">用户名</param>        /// <param name="passWord">密码</param>        /// <returns>Token信息</returns>        [HttpPost("login")]        public JSONResult Login(string username, string password)        {            var user = UserModel.Users.FirstOrDefault(x => x.UserName == username && x.UserPossword == password);            if (user == null)                return new jsonResult(                    new ResponseModel                    {                        Code = 0,                        Message = "登陆失败!"                    });            // 配置用户标识            var userClaims = new Claim[]            {                new Claim(ClaimTypes.Name,user.UserName),                new Claim(ClaimTypes.Role,user.Role),                new Claim(ClaimTypes.Expiration,DateTime.Now.AddMinutes(_requirement.Expiration.TotalMinutes).ToString()),            };            _requirement.SetRolesName(user.Role);            // 生成用户标识            var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);            identity.AddClaims(userClaims);            var token = JwtToken.BuildJwtToken(userClaims, _requirement);            return new JsonResult(                new ResponseModel                {                    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 (!(item.Issuer == AuthConfig.Issuer ?                    item.Audience == AuthConfig.Audience ?                    true : false : false))                {                    context.Fail();                }                // 校验过期时间                var nowTime = DateTimeOffset.Now.ToUnixTimeSeconds();                var issued = item.IssuedTime +Convert.ToInt64(item.Expiration.TotalSeconds);                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.Response.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 GetTokenSecurityKey()        {            var securityKey = new SigningCredentials(                new SymmetricSecurityKey(                    Encoding.UTF8.GetBytes(AuthConfig.SecurityKey)), SecurityAlgorithms.HMacSha256);            return securityKey;        }        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="username"></param>        /// <returns></returns>        public static dynamic BuildJwtToken(Claim[] claims, PermissionRequirement permissionRequirement)        {            var now = DateTime.UtcNow;            var jwt = new JwtSecurityToken(                issuer: permissionRequirement.Issuer,                audience: permissionRequirement.Audience,                claims: claims,                notBefore: now,                expires: now.Add(permissionRequirement.Expiration),                signingCredentials: permissionRequirement.SigningCredentials            );            var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);            var response = new            {                Status = true,                access_token = encodedJwt,                expires_in = permissionRequirement.Expiration.TotalMilliseconds,                token_type = "Bearer"            };            return response;        }

表示时间戳

// Unix 时间戳DateTimeOffset.Now.ToUnixTimeSeconds();// 检验 Token 是否过期// 将 TimeSpan 转为 Unix 时间戳Convert.ToInt64(TimeSpan);DateTimeOffset.Now.ToUnixTimeSeconds() + Convert.ToInt64(TimeSpan);

ASP.net 是什么

ASP.NET 是开源,跨平台,高性能,轻量级的 WEB 应用构建框架,常用于通过 htmlCSSjavascript 以及服务器脚本来构建网页和网站。

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注编程网精选频道,感谢您对编程网的支持。

--结束END--

本文标题: ASP.NET Core如何使用JWT自定义角色并实现策略授权需要的接口

本文链接: https://lsjlt.com/news/307305.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作