• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

.net core 使用jwt验证

武飞扬头像
wx64af93fcae71c
帮助1

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
系列文章
更多 icon
同类精品
更多 icon
继续加载