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

相关文章

在C#中获取端口号与系统信息的高效实践

《在C#中获取端口号与系统信息的高效实践》在现代软件开发中,尤其是系统管理、运维、监控和性能优化等场景中,了解计算机硬件和网络的状态至关重要,C#作为一种广泛应用的编程语言,提供了丰富的API来帮助开... 目录引言1. 获取端口号信息1.1 获取活动的 TCP 和 UDP 连接说明:应用场景:2. 获取硬

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

C#实现获取电脑中的端口号和硬件信息

《C#实现获取电脑中的端口号和硬件信息》这篇文章主要为大家详细介绍了C#实现获取电脑中的端口号和硬件信息的相关方法,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 我们经常在使用一个串口软件的时候,发现软件中的端口号并不是普通的COM1,而是带有硬件信息的。那么如果我们使用C#编写软件时候,如

C#实现WinForm控件焦点的获取与失去

《C#实现WinForm控件焦点的获取与失去》在一个数据输入表单中,当用户从一个文本框切换到另一个文本框时,需要准确地判断焦点的转移,以便进行数据验证、提示信息显示等操作,本文将探讨Winform控件... 目录前言获取焦点改变TabIndex属性值调用Focus方法失去焦点总结最后前言在一个数据输入表单

Java后端接口中提取请求头中的Cookie和Token的方法

《Java后端接口中提取请求头中的Cookie和Token的方法》在现代Web开发中,HTTP请求头(Header)是客户端与服务器之间传递信息的重要方式之一,本文将详细介绍如何在Java后端(以Sp... 目录引言1. 背景1.1 什么是 HTTP 请求头?1.2 为什么需要提取请求头?2. 使用 Spr

通过C#获取PDF中指定文本或所有文本的字体信息

《通过C#获取PDF中指定文本或所有文本的字体信息》在设计和出版行业中,字体的选择和使用对最终作品的质量有着重要影响,然而,有时我们可能会遇到包含未知字体的PDF文件,这使得我们无法准确地复制或修改文... 目录引言C# 获取PDF中指定文本的字体信息C# 获取PDF文档中用到的所有字体信息引言在设计和出

python中os.stat().st_size、os.path.getsize()获取文件大小

《python中os.stat().st_size、os.path.getsize()获取文件大小》本文介绍了使用os.stat()和os.path.getsize()函数获取文件大小,文中通过示例代... 目录一、os.stat().st_size二、os.path.getsize()三、函数封装一、os

python实现自动登录12306自动抢票功能

《python实现自动登录12306自动抢票功能》随着互联网技术的发展,越来越多的人选择通过网络平台购票,特别是在中国,12306作为官方火车票预订平台,承担了巨大的访问量,对于热门线路或者节假日出行... 目录一、遇到的问题?二、改进三、进阶–展望总结一、遇到的问题?1.url-正确的表头:就是首先ur

SpringBoot项目引入token设置方式

《SpringBoot项目引入token设置方式》本文详细介绍了JWT(JSONWebToken)的基本概念、结构、应用场景以及工作原理,通过动手实践,展示了如何在SpringBoot项目中实现JWT... 目录一. 先了解熟悉JWT(jsON Web Token)1. JSON Web Token是什么鬼

python获取当前文件和目录路径的方法详解

《python获取当前文件和目录路径的方法详解》:本文主要介绍Python中获取当前文件路径和目录的方法,包括使用__file__关键字、os.path.abspath、os.path.realp... 目录1、获取当前文件路径2、获取当前文件所在目录3、os.path.abspath和os.path.re