最近发现公司接口的验密方式很简单,就是简单的用户名密码校验。客户方面的负责人说要修改一下,所以想起了微信的验证密码的方式故写了这个Demo以供大家学习参考;
接口:WebService
方式:Token动态加密签名;
WebService头参数说明:Signature:加密签名,字符串类型;
Timestamp:当前时间戳,DateTime类型(注意客户端时间和服务端时间差不能大于7秒,可以修改)
Nonce:随机数,字符串类型;
参数处理:客户端用Token+ Timestamp+ Nonce后的字符串进行字典排序;
客户端将排序后的字符串进行MD5加密;
将加密后的字符串作为Signature参数传到服务端;
服务端代码:/// <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></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></param>
/// <param></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></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秒后则自动失效;
在API中Token的使用方法