当前位置: 首页 > news >正文

用Token令牌维护微服务之间的通信安全的实现

在微服务架构中,如果忽略服务的安全性,任由接口暴露在网络中,一旦遭受攻击后果是不可想象的、

保护微服务键安全的常见方案有:1.JWT令牌(token) 2.双向SSL 3.OAuth 2.0 等

本文主要介绍使用Token的实现方式

源码地址:https://github.com/Mike-Zrw/TokenApiAuth

基本流程:

上图中有两个服务,服务A和服务B,我们模拟的是服务A来调用服务B的过程,也可以反过来让服务B来调用服务A。

整个流程简单来说只有两步

  • 获取token
  • 携带token请求数据

获取token

服务端会提供一个产生token的接口供客户端来调用,而对于调用该接口的请求同样需要认证,否则岂不是所有人都可以随意调用该接口来生成token了。

我的思路是每个客户端会有一个权限标识,可以是一样的。然后将权限,时间戳和一个随机数组成一个字符串,然后将该字符串以非对称加密。加密后的字符就是调用接口的参数了

在token生成的服务端,会解密客户端传来的数据,并进行权限及时间的校验,验证通过就会生成一个token,该token用Aes对称加密,然后返回给客户端

一个token包含的结构如下

public class TokenClaims
{
    /// <summary> /// token的发行者 /// </summary> public string Iss { get; set; } /// <summary> /// 用户权限 /// </summary> public string Role { get; set; } /// <summary> /// 用户名 /// </summary> public string Usr { get; set; } /// <summary> /// 签发时间 秒 /// </summary> public long Iat { get; set; } /// <summary> /// 到期时间 秒 /// </summary> public long Exp { get; set; } /// <summary> /// 唯一标识 /// </summary> public string SingleStr { get; set; } }

其中用户名是服务端生成的,服务端会将该用户名作为键,将该token存储到缓存中。 所以对于每一个请求都会生成一个唯一的用户名,服务端会定期清理在缓存中已经失效的token

    public static TokenResult MakeToken(string RequestParam, string PrimaryKey = null) { try { dynamic p = JsonConvert.DeserializeObject(RequestParam); string RequestAuth = p.RequestAuth;//请求人信息 string DesAuth;//解密后的author if (PrimaryKey == null) DesAuth = RSAHelper.Decrypt(RequestAuth, Config_PrimaryKey); else DesAuth = RSAHelper.Decrypt(RequestAuth, PrimaryKey); #region 请求历史是否有重复 if (MakeTokenParamHistory.Contains(DesAuth)) { ToolFactory.LogHelper.Info("生成token身份验证失败:该请求的字符串与之前重复:" + DesAuth); return new TokenResult() { Success = false, Error_Message = "请求数据非法" }; } MakeTokenParamHistory.Insert(0, DesAuth); if (MakeTokenParamHistory.Count 1000) MakeTokenParamHistory.RemoveRange(1000, MakeTokenParamHistory.Count - 1000); #endregion string ReqAuthId = DesAuth.Substring(DesAuth.Length - 46, 10);//请求人身份标识 long reqTimespan = long.Parse(DesAuth.Substring(0, DesAuth.Length - 46)); //客户端请求时间秒数 if (!ValidTokenAuth(ReqAuthId)) { ToolFactory.LogHelper.Info("生成token身份验证失败:DesAuth" + DesAuth); return new TokenResult() { Success = false, Error_Message = "身份验证失败" }; } if ((TimeHelper.GetTimeSecond() - reqTimespan) ReqToken_OverTime) { ToolFactory.LogHelper.Info("生成token请求时间超时:DesAuth" + DesAuth); return new TokenResult() { Success = false, Error_Message = "请求时间超时" }; } string uname = TokenBuilder.CreateUserName(ReqAuthId); long TokenOverTime = Token_OverTime; if (AuthMapOverTime != null && AuthMapOverTime.ContainsKey(ReqAuthId)) TokenOverTime = AuthMapOverTime[ReqAuthId]; string tokenStr = TokenBuilder.CreateTokenStr("jwt", ReqAuthId, uname, TokenOverTime); ToolFactory.LogHelper.Notice("生成token:" + tokenStr); ToolFactory.CacheHelper.SetCache("ServiceTokenCacheKey_" + uname, tokenStr, TimeSpan.FromSeconds(TokenOverTime + 600)); //多存600秒 return new TokenResult() { Success = true, Token = AesHelper.Encrypt(tokenStr) }; ; } catch (Exception ex) { ToolFactory.LogHelper.Error("生成token出现异常", ex); return new TokenResult() { Success = false, Error_Message = "错误的请求:" + ex.Message }; } }

请求数据

对于携带token的请求,我将token放在http的header中,尽量减少验证对于业务代码的侵入性。

服务端将token取出,并或得token中存储的用户名,然后将服务端缓存的数据取出来判断该token是否有效

    /// <summary>
    /// 验证客户端发来的token是否有效 /// </summary> /// <param name="header"></param> /// <returns></returns> public static ValidTokenResult ValidClientToken(HttpRequestHeaders header) { if (header.Authorization == null || header.Authorization.Parameter == null) { return new ValidTokenResult() { Success = false, Message = "not exit token" }; } string tokenStr = AesHelper.Decrypt(header.Authorization.Parameter); //ToolFactory.LogHelper.Notice("接收到带token的请求:" + tokenStr); TokenClaims tcParam = TokenBuilder.ParseTokenClaims(tokenStr); TokenClaims tcCache = TokenBuilder.ParseTokenClaims(ToolFactory.CacheHelper.GetCache<string>("ServiceTokenCacheKey_" + tcParam.Usr)); if (tcCache != null) { if (TokenIsTimeLoss(tcCache.Exp)) { ToolFactory.LogHelper.Info("token过时,token:" + tokenStr); return new ValidTokenResult() { Success = false, Message = "token过时" }; } else if (tcCache.SingleStr != tcParam.SingleStr) { ToolFactory.LogHelper.Info("token不正确,token:" + tokenStr); return new ValidTokenResult() { Success = false, Message = "token不正确" }; } else { return new ValidTokenResult() { Success = true }; } } else { ToolFactory.LogHelper.Info("ValidClientToken未授权的用户,token:" + tokenStr); return new ValidTokenResult() { Success = false, Message = "未授权的用户" }; } }

整个验证框架的主要流程大概就是这样,当然还有很多细节,比如缓存的刷新,请求超时配置等等,有兴趣的可以到github下载具体代码~~~

转载于:https://www.cnblogs.com/itrena/p/8311235.html

相关文章:

  • Angular学习(一)
  • jsp:jstl标签forTokens
  • Fiddler Web Debugger的下载和安装(图文详解)
  • Navicat for MySQL出现1030-Got error 28 from storage engine错误
  • 通过config文件配置动态导入模块
  • 第二次C语言实验报告
  • ThinkPHP3.2 下载、导入Excel表格内容、导出内容到Excel表格功能的设计与实现
  • CORS跨域cookie传递
  • Python3 的元组
  • 【转】四款经典3.7v锂电池充电电路图详解
  • [TJOI2013]循环格
  • 6. python 字符串格式化表达式
  • tomcat 取消项目名访问路径
  • 【Python】学习笔记5-模块pymysql操作mysql数据库
  • mysql innodb myisam 比较
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • fetch 从初识到应用
  • React组件设计模式(一)
  • 大型网站性能监测、分析与优化常见问题QA
  • 对超线程几个不同角度的解释
  • 复杂数据处理
  • 记一次删除Git记录中的大文件的过程
  • 你不可错过的前端面试题(一)
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 通信类
  • 正则学习笔记
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • 积累各种好的链接
  • ​VRRP 虚拟路由冗余协议(华为)
  • ​决定德拉瓦州地区版图的关键历史事件
  • ​一些不规范的GTID使用场景
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • # 透过事物看本质的能力怎么培养?
  • #### golang中【堆】的使用及底层 ####
  • #QT(一种朴素的计算器实现方法)
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • (13)Hive调优——动态分区导致的小文件问题
  • (2)leetcode 234.回文链表 141.环形链表
  • (机器学习-深度学习快速入门)第三章机器学习-第二节:机器学习模型之线性回归
  • (十二)Flink Table API
  • (十七)、Mac 安装k8s
  • (五)IO流之ByteArrayInput/OutputStream
  • (一) 初入MySQL 【认识和部署】
  • (原創) 未来三学期想要修的课 (日記)
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)大道至简,职场上做人做事做管理
  • (转)大型网站的系统架构
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .java 指数平滑_转载:二次指数平滑法求预测值的Java代码
  • .NET delegate 委托 、 Event 事件,接口回调
  • .NET MVC第五章、模型绑定获取表单数据
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .net专家(张羿专栏)
  • .sh文件怎么运行_创建优化的Go镜像文件以及踩过的坑