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

2024-03-29 10:36

本文主要是介绍net core SSO 单点登录和控制器中获取Token和UserId,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

在写WebApi时常常是要获取登录用户的oken和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();//剔除Bearerstring mobile = "";//用户手机号//验证jwt,同时取出来jwt里边的用户IDTokenType 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){//LawcaseEvidenceFilePreviewif (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{//获取请求头中的Tokenvar 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里边的用户IDTokenType 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)//数据格式都不对直接passreturn 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)//数据格式都不对直接passreturn 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);//                                          ActionExecutingContextservices.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}}

END

这篇关于net core SSO 单点登录和控制器中获取Token和UserId的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/858368

相关文章

Win32下C++实现快速获取硬盘分区信息

《Win32下C++实现快速获取硬盘分区信息》这篇文章主要为大家详细介绍了Win32下C++如何实现快速获取硬盘分区信息,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 实现代码CDiskDriveUtils.h#pragma once #include <wtypesbase

Android如何获取当前CPU频率和占用率

《Android如何获取当前CPU频率和占用率》最近在优化App的性能,需要获取当前CPU视频频率和占用率,所以本文小编就来和大家总结一下如何在Android中获取当前CPU频率和占用率吧... 最近在优化 App 的性能,需要获取当前 CPU视频频率和占用率,通过查询资料,大致思路如下:目前没有标准的

基于.NET编写工具类解决JSON乱码问题

《基于.NET编写工具类解决JSON乱码问题》在开发过程中,我们经常会遇到JSON数据处理的问题,尤其是在数据传输和解析过程中,很容易出现编码错误导致的乱码问题,下面我们就来编写一个.NET工具类来解... 目录问题背景核心原理工具类实现使用示例总结在开发过程中,我们经常会遇到jsON数据处理的问题,尤其是

Oracle登录时忘记用户名或密码该如何解决

《Oracle登录时忘记用户名或密码该如何解决》:本文主要介绍如何在Oracle12c中忘记用户名和密码时找回或重置用户账户信息,文中通过代码介绍的非常详细,对同样遇到这个问题的同学具有一定的参... 目录一、忘记账户:二、忘记密码:三、详细情况情况 1:1.1. 登录到数据库1.2. 查看当前用户信息1.

golang获取prometheus数据(prometheus/client_golang包)

《golang获取prometheus数据(prometheus/client_golang包)》本文主要介绍了使用Go语言的prometheus/client_golang包来获取Prometheu... 目录1. 创建链接1.1 语法1.2 完整示例2. 简单查询2.1 语法2.2 完整示例3. 范围值

javaScript在表单提交时获取表单数据的示例代码

《javaScript在表单提交时获取表单数据的示例代码》本文介绍了五种在JavaScript中获取表单数据的方法:使用FormData对象、手动提取表单数据、使用querySelector获取单个字... 方法 1:使用 FormData 对象FormData 是一个方便的内置对象,用于获取表单中的键值

Node.js net模块的使用示例

《Node.jsnet模块的使用示例》本文主要介绍了Node.jsnet模块的使用示例,net模块支持TCP通信,处理TCP连接和数据传输,具有一定的参考价值,感兴趣的可以了解一下... 目录简介引入 net 模块核心概念TCP (传输控制协议)Socket服务器TCP 服务器创建基本服务器服务器配置选项服

MobaXterm远程登录工具功能与应用小结

《MobaXterm远程登录工具功能与应用小结》MobaXterm是一款功能强大的远程终端软件,主要支持SSH登录,拥有多种远程协议,实现跨平台访问,它包括多会话管理、本地命令行执行、图形化界面集成和... 目录1. 远程终端软件概述1.1 远程终端软件的定义与用途1.2 远程终端软件的关键特性2. 支持的

如何利用Java获取当天的开始和结束时间

《如何利用Java获取当天的开始和结束时间》:本文主要介绍如何使用Java8的LocalDate和LocalDateTime类获取指定日期的开始和结束时间,展示了如何通过这些类进行日期和时间的处... 目录前言1. Java日期时间API概述2. 获取当天的开始和结束时间代码解析运行结果3. 总结前言在J

修改若依框架Token的过期时间问题

《修改若依框架Token的过期时间问题》本文介绍了如何修改若依框架中Token的过期时间,通过修改`application.yml`文件中的配置来实现,默认单位为分钟,希望此经验对大家有所帮助,也欢迎... 目录修改若依框架Token的过期时间修改Token的过期时间关闭Token的过期时js间总结修改若依