文章出處

 

最近發現公司接口的驗密方式很簡單,就是簡單的用戶名密碼校驗。客戶方面的負責人說要修改一下,所以想起了微信的驗證密碼的方式故寫了這個Demo以供大家學習參考;

 

接口:WebService

 

方式:Token動態加密簽名;

 

名詞解釋:Token就是服務端和客戶端約定好的一個固定的密碼字符串。微信接口上這么寫的我就直接般過來了,結果有朋友不理解。

 

WebService頭參數說明:

 

Signature:加密簽名,字符串類型;

Timestamp:當前時間戳,DateTime類型(注意客戶端時間和服務端時間差不能大于7秒,可以修改)

Nonce:隨機數,字符串類型;

 

參數處理:

 

  1. 客戶端用Token+ Timestamp+ Nonce后的字符串進行字典排序;
  2. 客戶端將排序后的字符串進行MD5加密;
  3. 將加密后的字符串作為Signature參數傳到服務端;

 

服務端接受到參數后也是按照,自己的Token+客戶傳的Timestamp+客戶傳的 Nonce 然后同樣按照字典排序,MD5加密后和客戶端的Signature參數做對比,如果一致則驗證成功!(服務器要驗證客戶端傳入的時間戳參數和系統當前時間差值不能大于7秒,以保證口令過期后不能用)。

 

 

服務端代碼:

/// <summary>

    /// WebService接口 SoapHeader類

    /// </summary>

    public class APISoapHeader : System.Web.Services.Protocols.SoapHeader

    {

        /// <summary>

        ///  加密簽名

        /// </summary>

        public string signature { get; set; }

        /// <summary>

        /// 時間戳

        /// </summary>

        public DateTime timestamp{ get; set; }

        /// <summary>

        /// 隨機數

        /// </summary>

        public string nonce { get; set; }

    }

 

    /// <summary>

    /// WebService1 的摘要說明

    /// </summary>

    [WebService(Namespace = "http://tempuri.org/")]

    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

    [System.ComponentModel.ToolboxItem(false)]

    // 若要允許使用 ASP.NET AJAX 從腳本中調用此 Web 服務,請取消注釋以下行。

    // [System.Web.Script.Services.ScriptService]

    public class WebService1 : System.Web.Services.WebService

    {

        public APISoapHeader header { get; set; }

 

        [System.Web.Services.Protocols.SoapHeader("header")]

        [WebMethod]

        public string HelloWorld(string msg)

        {

            if (header != null && TokenHelper.TokenVerify(header.signature, header.timestamp, header.nonce))

            {

                return "Hello World:" + msg;

            }

            else

            {

                return "NO";

            }

        }

}

 

 

 

驗證代碼:

  public abstract class TokenHelper

    {

        /// <summary>

        /// 驗證加密簽名

        /// </summary>

        /// <param name="header"></param>

        /// <returns></returns>

        public static bool TokenVerify(string signature,DateTime timestamp, string nonce)

        {

 

            bool isok = false;

            if (!string.IsNullOrEmpty(signature)

                && !string.IsNullOrEmpty(nonce))

            {

                TimeSpan ts = DateTime.Now.Subtract(timestamp).Duration();

 

                if (ts.Seconds < 7)//如果請求端時間戳與系統時間差小于7秒則繼續驗證

                {

                    if (signature.Equals(TokenHelper.GetSignature(timestamp, nonce)))

                    {

                        return true;

                    }

                }

            }

 

            return isok;

        }

        /// <summary>

        /// 獲取加密簽名

        /// </summary>

        /// <param name="timestamp"></param>

        /// <param name="nonce"></param>

        /// <returns></returns>

        public static string GetSignature(DateTime timestamp, string nonce)

        {

            string token = System.Configuration.ConfigurationManager.AppSettings["APIToken"];

            string str = string.Format("{0}{1}{2}", token, timestamp.ToString(), nonce);

            List<char> str2 = str.ToList<char>();

            str2.Sort();

            string str3 = "";

            foreach (var item in str2)

            {

                str3 = string.Format("{0}{1}", str3, item.ToString());

            }

            return TokenHelper.MD5Encrypt(str3);

        }

        /// <summary>

        /// MD5加密

        /// </summary>

        /// <param name="strText"></param>

        /// <returns></returns>

        public static string MD5Encrypt(string strText)

        {

            string cryptStr = "";

            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();

            byte[] bytes = Encoding.UTF8.GetBytes(strText);

            byte[] cryptBytes = md5.ComputeHash(bytes);

            for (int i = 0; i < cryptBytes.Length; i++)

            {

                cryptStr += cryptBytes[i].ToString("X2");

            }

            return cryptStr;

        }

 

    }

 

測試代碼:

 

    class Program

    {

        static void Main(string[] args)

        {

          

 

            string msg = Console.ReadLine();

            ServiceReference1.WebService1SoapClient client = new ServiceReference1.WebService1SoapClient();

 

            ServiceReference1.APISoapHeader header = new ServiceReference1.APISoapHeader();

            Random random = new Random();

            header.timestamp = DateTime.Now;

            header.nonce = random.Next(0, 100).ToString();

            header.signature = TokenHelper.GetSignature(header.timestamp, header.nonce);

            //Thread.Sleep(7000);//如果大于7秒則失敗;

            msg = client.HelloWorld(header, msg);

 

 

          

            Console.WriteLine(msg);

 

            Console.ReadKey();

        }

    }

 

 

 

該方法的好處就是傳輸的密碼是隨時變化的,而且就算是第三方截獲了密碼,去根據兩個動態值解密也相當困難,而且截獲的密碼也只能用7秒,7秒后則自動失效;


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜

    大師兄 發表在 痞客邦 留言(0) 人氣()