• net core SSO 单点登录和控制器中获取Token和UserId


    控制器中注入

    [ApiController]
    //[Authorize]
    [ServiceFilter(typeof(LDAPPLoginFilter))]
    [Route("/file/api/[controller]/[action]")]
    public class BaseController : ControllerBase
    {
           public ITokenHelper _tokenHelper;
           public IHttpContextAccessor _httpContext;
    
    /// <summary>
            /// 当前用户ID
            /// </summary>
    
            public string CurrentUserId
            {
                get{
                    var userId = "00185770cfb24ccca22e14f8b9111111";
    
                    if (_httpContext != null && _tokenHelper != null)
                    {
                        var tokenobj = _httpContext.HttpContext.Request.Headers["Authorization"].ToString();
                        //读取配置文件中 的 秘钥
                        var secretKey = ConfigurationManager.JwtTokenConfig["Secret"];
                        string token = tokenobj.Split(" ")[1].ToString();//剔除Bearer
                        string mobile = "";//用户手机号
                                           //验证jwt,同时取出来jwt里边的用户ID
                        TokenType tokenType = _tokenHelper.ValiTokenState(token, secretKey
                            , a => a["iss"] == "test.cn" && a["aud"] == "test"
                            , action =>
                            {
                                userId = action["id"];
                                mobile = action["phone_number"];
                            });
                    }
    
                    return userId;
                }
            }
    
    }
    
    public FileServerController(ITokenHelper tokenHelper, IHttpContextAccessor httpContextAccessor)
    { 
    
    _tokenHelper = tokenHelper;
    _httpContext = httpContextAccessor;
    
    }

    调用

     登录过滤器 

    /// <summary>
        /// 用户登录过滤器 
        /// 需要登录时 Check请求头中的token字段
        /// </summary>
        public class LDAPPLoginFilter : Attribute, IActionFilter
        {
            private readonly ITokenHelper _tokenHelper;
    
            /// <summary>
            /// 通过依赖注入得到数据访问层实例
            /// </summary>
            /// <param name="tokenHelper"></param>
            public LDAPPLoginFilter(ITokenHelper tokenHelper)
            {
                _tokenHelper = tokenHelper;
            }
    
            public void OnActionExecuted(ActionExecutedContext context)
            {
    
            }
    
            /// <summary>
            /// 操作过滤器
            /// </summary>
            /// <param name="context">请求上下文</param>
            /// <param name="next">下一个过滤器或者终结点本身</param>
            /// <returns></returns>
            //async public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
            //{
    
            //    var descriptor = context.ActionDescriptor;
            //    // 当未标记为 AllowAnonymous 时再执行  
            //    if (!descriptor.EndpointMetadata.Any(p => p is IAllowAnonymous))
            //    {
            //        context.HttpContext.Request.Headers.TryGetValue("token", out var tokens);
            //        var token = tokens.FirstOrDefault();
            //        if (string.IsNullOrWhiteSpace(token))
            //        {
            //            //如果没有token 直接返回
            //            context.Result = new UnauthorizedResult();//直接返回401 统一请求返回的话,这里修改成统一需要登录的请求实体
            //        }
            //        else
            //        {
            //            var redisKey = $"_APP_Token_{token}";
    
            //            //存在token
            //            var userInfo = RedisClient.GetValue<CommonUserModel>(redisKey);
            //            if (userInfo == null)
            //            {
            //                context.Result = new UnauthorizedResult();//直接返回401 统一请求返回的话,这里修改成统一需要登录的请求实体
            //                return;
            //            }
            //            // RedisClient.SetValue(redisKey, userInfo, 180 * 24 * 60);//180天内登录一次就重新置成180天  暂时不启用,重复写入性能影响大,一个月写入一次。 写入缓存时需要设计 cachetime
            //            await next();
            //        }
    
            //    }
    
            //}
            /// <summary>
            /// 请求接口时进行拦截处理
            /// </summary>
            /// <param name="context"></param>
            public void OnActionExecuting(ActionExecutingContext context)
            {
                //LawcaseEvidenceFilePreview
                if (context.ActionDescriptor.EndpointMetadata.Any(it => it.GetType() == typeof(NoLDAPPLoginFilter)))
                {
                    return;
                }
                //Action 名称过滤
                if (context.ActionDescriptor.DisplayName.Contains("ActionName"))
                {
                    return;
                }
                //var ret = new Models.Commons.ResultInfoModel();
                var ret = new AjaxResult();
                try
                {
                    //获取请求头中的Token
                    var tokenobj = context.HttpContext.Request.Headers["Authorization"].ToString();
                    if (string.IsNullOrEmpty(tokenobj))
                    {
                        ret.state = (int)ResultCodeEnum.ApiUnauthorized;
                        ret.message = "接口未授权";
                        context.Result = new JsonResult(ret);
                        return;
                    }
    
                    //读取配置文件中 的 秘钥
                    var secretKey = ConfigurationManager.JwtTokenConfig["Secret"];
                    string token = tokenobj.Split(" ")[1].ToString();//剔除Bearer 
                    string userId = string.Empty;
                    string mobile = string.Empty;//用户手机号
    
                    //var token = getToken(context);
                    //验证jwt,同时取出来jwt里边的用户ID
                    TokenType tokenType = _tokenHelper.ValiTokenState(token, secretKey
                        , a => a["iss"] == "test.cn" && a["aud"] == "test"
                        , action =>
                        {
                            userId = action["id"];
                            mobile = action["phone_number"];
                        });
    
                    if (tokenType == TokenType.FormError)
                    {
                        ret.state = (int)ResultCodeEnum.ApiUnauthorized;
                        ret.message = "登录失效,请重新登录!";//token非法
                        context.Result = new JsonResult(ret);
                        return;
                    }
                    if (tokenType == TokenType.Fail)
                    {
                        ret.state = (int)ResultCodeEnum.ApiUnauthorized;
                        ret.message = "用户信息验证失败!";//token验证失败
                        context.Result = new JsonResult(ret);
                        return;
                    }
                    if (tokenType == TokenType.Expired)
                    {
                        ret.state = (int)ResultCodeEnum.ApiUnauthorized;
                        ret.message = "登录失效,请重新登录!";
                        context.Result = new JsonResult(ret);
                        return;
                    }
                    if (string.IsNullOrEmpty(userId))
                    {
                        //获取用户编号失败时,阻止用户继续访问接口
                        ret.state = (int)ResultCodeEnum.Error;
                        ret.message = "用户信息丢失";
                        context.Result = new JsonResult(ret);
                        return;
                    }
    
                    //自定义代码逻辑,  取出token中的 用户编号 进行 用户合法性验证即可
                    //。。。。。。。
                }
                catch (Exception ex)
                {
                    ret.state = (int)ResultCodeEnum.Error;
                    ret.message = "请求来源非法" + ex.Message.ToString();
                    context.Result = new JsonResult(ret);
                    return;
                }
            }
        }
    /// <summary>
        /// 
        /// </summary>
        public interface ITokenHelper
        {
            /// <summary>
            /// Token验证
            /// </summary>
            /// <param name="encodeJwt">token</param>
            /// <param name="secretKey">secretKey</param>
            /// <param name="validatePayLoad">自定义各类验证; 是否包含那种申明,或者申明的值</param>
            /// <returns></returns>
            bool ValiToken(string encodeJwt, string secretKey, Func<Dictionary<string, string>, bool> validatePayLoad = null);
    
            /// <summary>
            /// 带返回状态的Token验证
            /// </summary>
            /// <param name="encodeJwt">token</param>
            /// <param name="secretKey">secretKey</param>
            /// <param name="validatePayLoad">自定义各类验证; 是否包含那种申明,或者申明的值</param>
            /// <param name="action"></param>
            /// <returns></returns>
            TokenType ValiTokenState(string encodeJwt, string secretKey, Func<Dictionary<string, string>, bool> validatePayLoad, Action<Dictionary<string, string>> action);
        }
    /// <summary>
        /// 
        /// </summary>
        public class TokenHelper : ITokenHelper
        {
            /// <summary>
            /// 验证身份 验证签名的有效性
            /// </summary>
            /// <param name="encodeJwt"></param>
            /// <param name="secretKey">配置文件中取出来的签名秘钥</param>
            /// <param name="validatePayLoad">自定义各类验证; 是否包含那种申明,或者申明的值, </param>
            public bool ValiToken(string encodeJwt, string secretKey, Func<Dictionary<string, string>, bool> validatePayLoad = null)
            {
                var success = true;
                var jwtArr = encodeJwt.Split('.');
                if (jwtArr.Length < 3)//数据格式都不对直接pass
                    return false;
                var payLoad = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[1]));
                //配置文件中取出来的签名秘钥
                var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(secretKey));
                //验证签名是否正确(把用户传递的签名部分取出来和服务器生成的签名匹配即可)
                success = success && string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1])))));
                if (!success)
                    return success;//签名不正确直接返回
                //其次验证是否在有效期内(也应该必须)
                var now = ToUnixEpochDate(DateTime.UtcNow);
                success = success && (now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString()));
    
                //不需要自定义验证不传或者传递null即可
                if (validatePayLoad == null)
                    return true;
                //再其次 进行自定义的验证
                success = success && validatePayLoad(payLoad);
                return success;
            }
    
            /// <summary>
            /// 时间转换
            /// </summary>
            /// <param name="date"></param>
            /// <returns></returns>
            private long ToUnixEpochDate(DateTime date)
            {
                return (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);
            }
    
            /// <summary>
            /// 
            /// </summary>
            /// <param name="encodeJwt"></param>
            /// <param name="secretKey"></param>
            /// <param name="validatePayLoad"></param>
            /// <param name="action"></param>
            /// <returns></returns>
            public TokenType ValiTokenState(string encodeJwt, string secretKey, Func<Dictionary<string, string>, bool> validatePayLoad, Action<Dictionary<string, string>> action)
            {
                //iss: jwt签发者
                //sub: jwt所面向的用户
                //aud: 接收jwt的一方
                //exp: jwt的过期时间,这个过期时间必须要大于签发时间
                //nbf: 定义在什么时间之前,该jwt都是不可用的
                //iat: jwt的签发时间
                //jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
    
                var jwtArr = encodeJwt.Split('.');
                if (jwtArr.Length < 3)//数据格式都不对直接pass
                    return TokenType.FormError;
                //var header = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[0]));
                var payLoad = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[1]));
                var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(secretKey));
                //验证签名是否正确(把用户传递的签名部分取出来和服务器生成的签名匹配即可)
                if (!string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1]))))))
                    return TokenType.FormError;
                var now = ToUnixEpochDate(DateTime.UtcNow);
                var nbf = long.Parse(payLoad["nbf"].ToString());
                var exp = long.Parse(payLoad["exp"].ToString());
                if (!(now >= nbf && now < exp))
                {
                    action(payLoad);
                    return TokenType.Expired;
                }
                //不需要自定义验证不传或者传递null即可
                if (validatePayLoad == null)
                {
                    action(payLoad);
                    return TokenType.Ok;
                }
                //再其次 进行自定义的验证
                if (!validatePayLoad(payLoad))
                    return TokenType.Fail;
                //可能需要获取jwt摘要里边的数据,封装一下方便使用
                action(payLoad);
                return TokenType.Ok;
            }
        }
    public class TokenManagement
        {
            public string Secret { get; set; }
    
            public string Issuer { get; set; }
    
            public string Audience { get; set; }
    
            public int AccessExpiration { get; set; }
            public int RefreshExpiration { get; set; }
        }
    public class NoLDAPPLoginFilter : Attribute, IActionFilter
        {
            public void OnActionExecuted(ActionExecutedContext context)
            {
            }
    
            public void OnActionExecuting(ActionExecutingContext context)
            {
                //var ret = new Models.Commons.ResultInfoModel();
                //ret.Head.ErrorCode = 1000;
                //ret.Head.Msg = "成功!";
                //context.Result = new JsonResult(ret);
            }
        }
    /// <summary>
        /// 设置该方法不会进行AES加密和解密操作,直接传入参数和响应结果 
        /// </summary>
        [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
        public class NoAESMiddlewareAttribute : Attribute
        {
        }
    public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
    
                LD.Code.ConfigurationManager.Configure(Configuration);
                //注册日志功能
                LD.Code.LogFactory.ResisterLogger();
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                //services.AddSwaggerGen(options =>
                //{
                //    #region  文档格式化
                //    options.SwaggerDoc("v1", new OpenApiInfo
                //    {
                //        Version = "V1",
                //        Title = "ASP.NET CORE WepbApi 3.1",
                //        Description = "基于Asp.Net Core 3.1 实现文件上传下载",
                //        Contact = new OpenApiContact
                //        {
                //            Name = "律盾",
                //            Email = "lvduntech@lvdun.com"
                //        },
                //        License = new OpenApiLicense
                //        {
                //            Name = "许可证",
                //        }
                //    });
                //    options.DocumentFilter<HiddenApiFilter>();
    
                //    #endregion
    
    
                //});
                services.AddSwaggerGen(c =>
                {
                    c.SwaggerDoc("v1", new OpenApiInfo { Title = "XXX服务接口", Version = "v1" });
                    // 获取xml文件名
                    var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                    // 获取xml文件路径
                    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                    // 添加控制器层注释,true表示显示控制器注释
                    c.IncludeXmlComments(xmlPath, true);
                    ////LD.Domain.xml
                    //xmlFile = "LD.Domain.xml";
                    //xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                    //c.IncludeXmlComments(xmlPath, true);
                    ////LD.Code.xml
                    //xmlFile = "LD.Code.xml";
                    //xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                    //c.IncludeXmlComments(xmlPath, true);
                    c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
                    c.DocumentFilter<HiddenApiFilter>();
                });
    
                services.Configure<TokenManagement>(Configuration.GetSection("JwtTokenConfig"));
                var token = Configuration.GetSection("JwtTokenConfig").Get<TokenManagement>();
                services.AddAuthentication(x =>
                {
                    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                }).AddJwtBearer(x =>
                {
                    x.RequireHttpsMetadata = false;
                    x.SaveToken = true;
                    x.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(token.Secret)),
                        ValidIssuer = token.Issuer,
                        ValidAudience = token.Audience,
                        ValidateIssuer = false,
                        ValidateAudience = false
                    };
                });
    
    
                LD.Services.RegisterIoc.Register(services);
                //                                          ActionExecutingContext
                services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
                services.AddTransient<ITokenHelper, TokenHelper>();
                services.AddScoped<NoLDAPPLoginFilter>();
                services.AddScoped<LDAPPLoginFilter>();
    
                services.AddControllers();
                //跨域
                var corsstring = Configuration.GetSection("Cors").Value;
                string[] corsarray = corsstring.Split(',');
    
                services.AddCors(options => options.AddPolicy("CorsPolicy",
                builder =>
                {
                    builder.AllowAnyMethod().AllowAnyHeader()
                           .WithOrigins(corsarray)
                           .AllowCredentials();
                }));
            }
            
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                //if (env.IsDevelopment())
                //{
                //    app.UseDeveloperExceptionPage();
                //}
                DocExpansion swaggeerDoc;
                //if (env.IsDevelopment())
                //{
                app.UseDeveloperExceptionPage();
                swaggeerDoc = DocExpansion.List;
    
                //添加Swagger有关中间件
                app.UseSwagger();
                app.UseSwaggerUI(c =>
                {
                    c.SwaggerEndpoint("/swagger/v1/swagger.json", "FileServerAPI  v1");
                    c.RoutePrefix = string.Empty;
                    c.DocExpansion(DocExpansion.None);
                });
                //}
                //else
                //{
    
                //    swaggeerDoc = DocExpansion.None;
                //}
                 app.UseStaticFiles();
                //app.UseStaticFiles(new StaticFileOptions
                //{                //设置不限制content-type
                //    ServeUnknownFileTypes = true
                //});
                app.UseHttpsRedirection();
    
                app.UseRouting();//1.路由
                app.UseCors("CorsPolicy");
                app.UseAuthentication();//2.认证
                app.UseAuthorization();//3.授权
                
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                });
                //app.UseSwagger();
                //app.UseSwaggerUI(c =>
                //{
                //    c.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1");
                //});
            }
        }
    public class Enum
        {
            /// <summary>
            /// 系统数据返回状态
            /// </summary>
            public enum ResultCodeEnum
            {
                /// <summary>
                /// 失败
                /// </summary>
                [Description("失败")]
                Error = 0,
    
                /// <summary>
                /// 成功
                /// </summary>
                [Description("成功")]
                Success = 1,
    
                /// <summary>
                /// 接口未授权
                /// </summary>
                [Description("接口未授权")]
                ApiUnauthorized = 401
    
            }
    
            /// <summary>
            /// 
            /// </summary>
            public enum TokenType
            {
                /// <summary>
                /// 验证成功
                /// </summary>
                [Description("验证成功")]
                Ok,
    
                /// <summary>
                /// 验证失败
                /// </summary>
                [Description("验证失败")]
                Fail,
    
                /// <summary>
                /// Token失效
                /// </summary>
                [Description("Token失效")]
                Expired,
    
                /// <summary>
                /// Token非法
                /// </summary>
                [Description("Token非法")]
                FormError
            }
        }
  • 相关阅读:
    .net 流读取
    c#小Tip:数字格式化显示
    VS.NET优化编译速度
    Application.Run()和Form.Show()的区别
    如何利用系统函数操作文件夹及文件
    设计优秀的用户界面
    我妈过来了
    帮你免于失业的十大软件技术(转抄)
    正试图在 OS 加载程序锁内执行托管代码
    NASA World Wind
  • 原文地址:https://www.cnblogs.com/stevenchen2016/p/16695393.html
Copyright © 2020-2023  润新知