首页 > 其他分享 >.net之 Jwt授权

.net之 Jwt授权

时间:2025-01-07 15:57:52浏览次数:7  
标签:return Jwt options token new var 授权 net public

概念

集成ASP.NET Core authorization JWT

引用阿里云包

项目文件总览

定义Jwt授权策略处理器

     /// <summary>
    /// 定义Jwt授权策略处理器
    /// </summary>
    internal class JwtAuthorizationHandler : AuthorizationHandler<JwtAuthorizationRequirement>
    {
        readonly IServiceProvider _serviceProvider;
        readonly IHttpContextAccessor _httpContextAccessor;
        readonly JwtAuthorizationOptions _jwtAuthorizationOptions;
        public JwtAuthorizationHandler(IHttpContextAccessor httpContextAccessor, IServiceProvider serviceProvider, IOptions<JwtAuthorizationOptions> jwtAuthorizationOptions)
        {
            _httpContextAccessor = httpContextAccessor;
            _serviceProvider = serviceProvider;
            _jwtAuthorizationOptions = jwtAuthorizationOptions.Value;
        }

        /// <summary>
        ///  Makes a decision if authorization is allowed.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="requirement"></param>
        /// <returns></returns>
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, JwtAuthorizationRequirement requirement)
        {
            var authResult = await _httpContextAccessor.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
            if (authResult.Succeeded && authResult.Principal.Identity.IsAuthenticated)
            {
                if (_jwtAuthorizationOptions.HandleAuthorization != null)
                {
                    if (await _jwtAuthorizationOptions.HandleAuthorization.Invoke((_serviceProvider, _httpContextAccessor.HttpContext, context)))
                    {
                        context.Succeed(requirement);
                        return;
                    }
                }
                context.Succeed(requirement);
                return;
            }
            context.Fail();
        }
    }


JwtAuthorizationOptions

     public class JwtAuthorizationOptions
    {
        /// <summary>
        /// 秘钥
        /// </summary>
        public string SecurityKey { get; set; }

        /// <summary>
        /// 令牌过期时间(单位:分钟)
        /// </summary>
        public double ExpiredMinutes { get; set; }

        /// <summary>
        /// 是否验证过期时间
        /// </summary>
        public bool ValidateLifetime { get; set; } = true;

        /// <summary>
        /// 过期时间容错值(单位:秒)
        /// </summary>
        public int ClockSkewSecond { get; set; } = 5;

        /// <summary>
        /// 签发方
        /// </summary>
        public string Issuer { get; set; }

        /// <summary>
        /// 签收方
        /// </summary>
        public string Audience { get; set; }

        /// <summary>
        /// 系统授权通过时,进行下一步自定义业务授权处理
        /// </summary>
        public Func<(IServiceProvider ServiceProvider, HttpContext HttpContext, AuthorizationHandlerContext AuthorizationHandlerContext), Task<bool>> HandleAuthorization { get; set; }
    }


JwtAuthorizationRequirement

   /// <summary>
    /// 定义Jwt授权策略
    /// </summary>
    internal class JwtAuthorizationRequirement: IAuthorizationRequirement
    {
    }

JwtBearerService

  public class JwtBearerService : IJwtService
    {
        private readonly JwtSecurityTokenHandler _jwtSecurityTokenHandler;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly JwtAuthorizationOptions _options;
        public JwtBearerService(IHttpContextAccessor httpContextAccessor, IOptions<JwtAuthorizationOptions> options)
        {
            _jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
            _httpContextAccessor = httpContextAccessor;
            _options = options.Value;
        }

        #region 创建令牌
        /// <summary>
        /// 创建令牌
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="identity"></param>
        /// <param name="claims"></param>
        /// <returns></returns>
        public virtual JwtInfo CreateAccessToken<T>(T identity, Dictionary<string, object> claims = null) where T : UserIdentityBase
        {
            var authUtc = DateTime.UtcNow;
            //过期时间
            var expiresUtc = authUtc.AddMinutes(_options.ExpiredMinutes);

            claims ??= new Dictionary<string, object>();
            claims[ClaimTypes.Expiration] = expiresUtc.ToString();

            var jwtToken = new JwtSecurityToken
                (
                    _options.Issuer,
                    _options.Audience,
                    identity.CreateClaims(claims),
                    authUtc,
                    expiresUtc,
                    new SigningCredentials
                    (
                        new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.SecurityKey)),
                        SecurityAlgorithms.HmacSha256
                    )
                );
            var accessToken = _jwtSecurityTokenHandler.WriteToken(jwtToken);
            var jwt = new JwtInfo()
            {
                AccessToken = accessToken,
                AccessTokenUtcExpires = expiresUtc,
                AuthUtc = authUtc,
                UserId = identity.Id
            };

            return jwt;
        }
        #endregion

        #region 获取当前上下文用户申明信息
        /// <summary>
        /// 获取当前上下文用户申明信息
        /// </summary>
        /// <returns></returns>
        public virtual T GetHttpContextUserIdentity<T>() where T : UserIdentityBase
        {
            T result = default;
            if (_httpContextAccessor?.HttpContext?.User?.Identity?.IsAuthenticated ?? false)
                result = ((ClaimsIdentity)_httpContextAccessor.HttpContext.User.Identity).ToObject<T>();
            return result;
        }
        #endregion
    }

JwtTokenTransferMiddleware

   internal class JwtTokenTransferMiddleware
    {
        private readonly RequestDelegate _next;
        JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
        public JwtTokenTransferMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            try
            {
                var token = HttpContextHelper.QueryHeader<string>(BPAHeader.AuthorizationHeaderKey);
                if (!token.HasVal())
                    token = HttpContextHelper.QueryString<string>(BPAHeader.AuthorizationTokenUrlKey);
                if (token.HasVal())
                {
                    if (!token.StartsWith(BPAHeader.JwtBearerAuthenticationScheme))
                        token = BPAHeader.JwtBearerAuthenticationScheme + token;
                  if(IsCanReadToken(token)) 
                        
                    context.Request.Headers[BPAHeader.AuthorizationHeaderKey] = token;
                }
            }
            finally
            {
                await _next(context);
            }
        }


        /// <summary>
        /// Token是否是符合要求的标准 Json Web 令牌
        /// </summary>
        /// <param name="tokenStr"></param>
        /// <returns></returns>
        private bool IsCanReadToken(string tokenStr)
        {
            if (string.IsNullOrWhiteSpace(tokenStr) || tokenStr.Length < 7)
                return false;
            if (!tokenStr.Substring(0, 6).Equals(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme))
                return false;
            tokenStr = tokenStr.Substring(7);
            bool isCan = jwtSecurityTokenHandler.CanReadToken(tokenStr);
            var jwt = jwtSecurityTokenHandler.ReadJwtToken(tokenStr);
            return isCan;
        }
    }

AuthorizationResultTransformer(授权结果转换)

    /// <summary>
    /// 授权结果转换器
    /// </summary>
    internal class AuthorizationResultTransformer : IAuthorizationMiddlewareResultHandler
    {
        private readonly IAuthorizationMiddlewareResultHandler _handler;

        public AuthorizationResultTransformer()
        {
            _handler = new AuthorizationMiddlewareResultHandler();
        }

        public async Task HandleAsync(
            RequestDelegate requestDelegate,
            HttpContext httpContext,
            AuthorizationPolicy authorizationPolicy,
            PolicyAuthorizationResult policyAuthorizationResult)
        {
            if (!policyAuthorizationResult.Succeeded)
            {
                var apiEvent = httpContext.RequestServices.GetService<IApiEventHandler>();
                if (apiEvent != null)
                {
                    await apiEvent.OnAuthorizationFailAsync(httpContext, authorizationPolicy, policyAuthorizationResult);
                }

                httpContext.Response.ContentType = "application/json;charset=utf-8";
                httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
                await httpContext.Response.WriteAsync
                (
                    new ApiResult(ApiResultCode.Unauthorized, SpecificationTip.AuthorizationFail)
                    {
                        TrackId = HttpContextHelper.TrackId
                    }.ToJson(BPASerializer.Json)
                );
                return;
            }

            await _handler.HandleAsync(requestDelegate, httpContext, authorizationPolicy, policyAuthorizationResult);
        }
    }

中间件封装

  public static class ApplicationBuilderExtensions
    {
        public static IApplicationBuilder UseJwtAuthorization(this IApplicationBuilder app)
        {
            app.UseMiddleware<JwtTokenTransferMiddleware>();
            //鉴权(检测是否登录,解析请求登录携带的信息,赋值给HttpContext.User)
            app.UseAuthentication();
            //授权 (检测权限)
            app.UseAuthorization();
            return app;
        }
    }

服务扩展

  public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddJwtAuthorization(this IServiceCollection services, Action<JwtAuthorizationOptions> setup)
        {
            services.Configure(setup);
            //启用身份验证中间件,身份验证方案(bearer)
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(op =>
                {
                    
                    var options = services.BuildServiceProvider().GetRequiredService<IOptions<JwtAuthorizationOptions>>().Value;
                    //获取或设置用于验证标识令牌的参数
                    op.TokenValidationParameters = new TokenValidationParameters
                    {
                        //是否验证发行者签发密钥
                        ValidateIssuerSigningKey = true,
                        //发行者签发密钥
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(options.SecurityKey)),
                        //
                        ValidateIssuer=false,
                        //发行者
                        ValidIssuer = options.Issuer,
                        ValidAudience = options.Audience,
                        ValidateLifetime = options.ValidateLifetime,
                        ClockSkew = TimeSpan.FromSeconds(options.ClockSkewSecond)
                       
                    };
                    op.Events = new JwtBearerEvents() {

                        OnMessageReceived = (context) => {
                            if (!context.HttpContext.Request.Path.HasValue)
                            {
                                return Task.CompletedTask;
                            }
                            
                            //重点在于这里;判断是Signalr的路径
                            var accessToken = context.HttpContext.Request.Query["access_token"];
                            var path = context.HttpContext.Request.Path;
                            Console.WriteLine(path);
                            Console.WriteLine(accessToken);
                            if (!(string.IsNullOrWhiteSpace(accessToken)) && path.StartsWithSegments("/chatHub"))
                            {
                                context.Token = accessToken;
                                return Task.CompletedTask;
                            }
                            return Task.CompletedTask;
                        }
                    };
                }
                );
            //启用权限验证
            services.AddAuthorization(options =>
            {
                options.AddPolicy(BPAPolicyNames.JwtBearer, policy => policy.Requirements.Add(new JwtAuthorizationRequirement()));
            });

            services.AddTransient<IJwtService, JwtBearerService>();
            services.AddTransient<IAuthorizationHandler, JwtAuthorizationHandler>();
            services.AddTransient<IAuthorizationMiddlewareResultHandler, AuthorizationResultTransformer>();
            // 注入当前用户,替换Thread.CurrentPrincipal的作用
            services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>()?.HttpContext?.User);

            return services;
        }

    }

打包传送门 https://www.cnblogs.com/inclme/p/16053978.html

.net6中使用

引用上述nuget包

添加扩展服务

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddJwtAuthorization((op) =>
{
    builder.Configuration.Bind("BPA:Jwt", op);
    //这里配置自定义业务授权处理,比如检查redis token是否存在。。
    op.HandleAuthorization = async (o) =>
    {
        return await Task.FromResult(true);
    };
});


var app = builder.Build();
app.UseJwtAuthorization();

使用示例

  public class BPAUserIdentity : UserIdentityBase
    {
        [Claim("test/companyid")]
        public string CompanyId { get; set; }
        [Claim]
        public string RoleId { get; set; }
    }
   /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<JwtInfo> SignInAsync(SignInRequest request)
        {
            request.Pwd = EncryptHelper.DesEncrypt(request.Pwd, "~1@Aa*<>");
            var token = _jwtService.CreateAccessToken(new BPAUserIdentity()
            {
                Id = IdGenerator.NextId(),
                UserName = request.UserName
            });
            return await Task.FromResult(token);
        }

标签:return,Jwt,options,token,new,var,授权,net,public
From: https://www.cnblogs.com/inclme/p/18657666

相关文章

  • AppDomainManager注入是一种针对.NET应用程序的高级攻击技术,攻击者通过操控AppDomain
    什么是APPDomainManager注入?APPDomainManager注入通常涉及到利用**应用程序域(AppDomain)**来执行恶意操作,特别是在.NET环境下。要理解这个概念,我们需要了解几个关键术语:AppDomain:在.NET应用程序中,AppDomain是一个隔离的执行环境,它允许多个应用程序或应用程序的不同部分在同一进......
  • .net6之阿里云OSS
    概念集成阿里云OSS文件存储服务引用阿里云包封装AliyunSmsClient(二次封装阿里云短信基类)publicclassAliyunOssClient{privatereadonlyAliyunOssOptions_options;privatereadonlyOssClient_client;publicAliyunOssClient(IOpt......
  • Javascript实现asp.net mvc的checkbox基本功能
    Html的checkbox使用很广的,它的状态,勾选与非选。 初始状态,默认为非选。你可以设置它是勾选,直在checkbox标签中,添加checked属性。另外,在javascript可以这样,getById('Checkbox_IsPublished').checked=true; 或者,getById('Checkbox_IsPublished').setAttribute('chec......
  • 深入解析IPoIB网络设备的驱动实现:net_device_ops与ipoib_open函数
    在Linux内核中,网络设备的驱动实现通常通过net_device_ops结构体来定义设备的各种操作函数。本文将以IPoverInfiniBand(IPoIB)设备的驱动实现为例,深入分析net_device_ops结构体的定义以及ipoib_open函数的实现细节。通过这段代码,我们可以了解如何在内核中实现网络设备的初始化、......
  • BotSharp:又一个.Net重磅AI开源项目,.Net在AI领域开始崛起!
    大家好,我是编程乐趣。自从大模型爆火以来,.Net不管是官方、还是社区开源项目,都陆续推出很多重磅的项目。在AI领域,对话即平台(CaaP)是未来的发展方向。下面介绍一个开源项目,面向AIBot平台构建者的开源机器学习框架:BotSharp,它已经为.NET开发人员提供了使用BotSharpAIBOTplatform......
  • 公共数据授权运营机制建设(六大机制、存在问题、发展路径)
    前言在国家战略部署下,学界和各地方政府从理论和实践两个层面积极探索公共数据授权运营机制。本期将从学理上剖析公共数据授权运营的基本内容,说明公共数据授权运营到底包括哪些内容,并且举例说明各地在公共数据授权运营机制建设方面的典型经验和做法;其次,说明公共数据授权运营机制......
  • Scalable Methods for 8-bit Training of Neural Networks
    目录概RangeBatchNormalization代码BannerR.,HubaraI.,HofferE.andSoudryD.Scalablemethodsfor8-bittrainingofneuralnetworks.NeurIPS,2018.概本文针对BatchNorm模块在低精度(8-bit)的情况下进行一个合适的改进.RangeBatchNormalization对于......
  • .NET Core GC对象 分配(GC Alloc)底层原理浅谈
    对象分配策略.NET程序的对象是由CLR控制并分配在托管堆中,如果是你,会如何设计一个内存分配策略呢?按需分配,要多少分配多少,移动alloc_ptr指针即可,没有任何浪费。缺点是每次都要向OS申请内存,效率低预留缓冲区,降低了向OS申请内存的频次。但在多线程情况下,alloc_ptr锁竞争会非常......
  • 第四章、连上 Internet
    4.1Linux连上Internet前的注意事项由前面几章的数据我们知道,想要连上Internet你得要设定一组合法的IP参数才可以,主要是IP,Netmask,Gateway,DNSIP以及主机名等。那我们也知道,其实整个主机最重要的设定,就是『先要驱动网络卡』,否则主机连网络卡都捉不到时,怎么设......
  • [.NET] API网关选择:YARP还是Ocelot?
    API网关选择:YARP还是Ocelot?摘要随着微服务架构的流行,API网关在系统架构中扮演着越来越重要的角色。在.NET生态中,YARP(YetAnotherReverseProxy)和Ocelot是两种常用的API网关解决方案。那么,在实际应用中,我们该如何选择?本文将从易用性、文档、负载均衡、限流、身份验证、授权和性......