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

相关文章

JWT + 拦截器实现无状态登录系统

《JWT+拦截器实现无状态登录系统》JWT(JSONWebToken)提供了一种无状态的解决方案:用户登录后,服务器返回一个Token,后续请求携带该Token即可完成身份验证,无需服务器存储会话... 目录✅ 引言 一、JWT 是什么? 二、技术选型 三、项目结构 四、核心代码实现4.1 添加依赖(pom

Go语言使用net/http构建一个RESTful API的示例代码

《Go语言使用net/http构建一个RESTfulAPI的示例代码》Go的标准库net/http提供了构建Web服务所需的强大功能,虽然众多第三方框架(如Gin、Echo)已经封装了很多功能,但... 目录引言一、什么是 RESTful API?二、实战目标:用户信息管理 API三、代码实现1. 用户数据

在ASP.NET项目中如何使用C#生成二维码

《在ASP.NET项目中如何使用C#生成二维码》二维码(QRCode)已广泛应用于网址分享,支付链接等场景,本文将以ASP.NET为示例,演示如何实现输入文本/URL,生成二维码,在线显示与下载的完整... 目录创建前端页面(Index.cshtml)后端二维码生成逻辑(Index.cshtml.cs)总结

Spring Security重写AuthenticationManager实现账号密码登录或者手机号码登录

《SpringSecurity重写AuthenticationManager实现账号密码登录或者手机号码登录》本文主要介绍了SpringSecurity重写AuthenticationManage... 目录一、创建自定义认证提供者CustomAuthenticationProvider二、创建认证业务Us

Springboot项目登录校验功能实现

《Springboot项目登录校验功能实现》本文介绍了Web登录校验的重要性,对比了Cookie、Session和JWT三种会话技术,分析其优缺点,并讲解了过滤器与拦截器的统一拦截方案,推荐使用JWT... 目录引言一、登录校验的基本概念二、HTTP协议的无状态性三、会话跟android踪技术1. Cook

解决hive启动时java.net.ConnectException:拒绝连接的问题

《解决hive启动时java.net.ConnectException:拒绝连接的问题》Hadoop集群连接被拒,需检查集群是否启动、关闭防火墙/SELinux、确认安全模式退出,若问题仍存,查看日志... 目录错误发生原因解决方式1.关闭防火墙2.关闭selinux3.启动集群4.检查集群是否正常启动5.

使用Redis快速实现共享Session登录的详细步骤

《使用Redis快速实现共享Session登录的详细步骤》在Web开发中,Session通常用于存储用户的会话信息,允许用户在多个页面之间保持登录状态,Redis是一个开源的高性能键值数据库,广泛用于... 目录前言实现原理:步骤:使用Redis实现共享Session登录1. 引入Redis依赖2. 配置R

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

Python获取浏览器Cookies的四种方式小结

《Python获取浏览器Cookies的四种方式小结》在进行Web应用程序测试和开发时,获取浏览器Cookies是一项重要任务,本文我们介绍四种用Python获取浏览器Cookies的方式,具有一定的... 目录什么是 Cookie?1.使用Selenium库获取浏览器Cookies2.使用浏览器开发者工具

Java获取当前时间String类型和Date类型方式

《Java获取当前时间String类型和Date类型方式》:本文主要介绍Java获取当前时间String类型和Date类型方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录Java获取当前时间String和Date类型String类型和Date类型输出结果总结Java获取