雏菊种子什么时候播种最好? 当前位置:首页>雏菊种子什么时候播种最好?>正文

雏菊种子什么时候播种最好?

发布时间:2019-04-21

原标题:用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下载具体代码~~~

当前文章:http://www.dehangcd.com/8b9p2.html

发布时间:2019-04-21 07:04:38

哪里有卖野生薄荷草籽? 金盏菊和洋甘菊有什么区别? 马鞭草种子今年什么价格? 美女樱种子今年什么价格? 6月可以播种芒果吗? 苦楝树花期是什么时候呢? 9月可以播种油松吗? 重楼种子每亩地用多少斤? 一米高的塔柏价格是多少? 蔷薇扦插苗批发去哪里?

91397 17898 65483 59871 58007 30355 22457 70924 63004 31358 56784 45095 19799 99032 54072 92527 96360 52761 15713 37088 76093 29229 70638

责任编辑:通纯伯公