最近發現公司接口的驗密方式很簡單,就是簡單的用戶名密碼校驗。客戶方面的負責人說要修改一下,因此想起了微信的驗證密碼的方式故寫了這個Demo以供你們學習參考;服務器
接口:WebService微信
方式:Token動態加密簽名;dom
名詞解釋:Token就是服務端和客戶端約定好的一個固定的密碼字符串。微信接口上這麼寫的我就直接般過來了,結果有朋友不理解。ide
Signature:加密簽名,字符串類型;學習
Timestamp:當前時間戳,DateTime類型(注意客戶端時間和服務端時間差不能大於7秒,能夠修改)測試
Nonce:隨機數,字符串類型;加密
服務端接受到參數後也是按照,本身的Token+客戶傳的Timestamp+客戶傳的 Nonce 而後一樣按照字典排序,MD5加密後和客戶端的Signature參數作對比,若是一致則驗證成功!(服務器要驗證客戶端傳入的時間戳參數和系統當前時間差值不能大於7秒,以保證口令過時後不能用)。spa
/// <summary>orm
/// 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秒後則自動失效;