标签:convert ctc type oid dict int pre tco color
上一章记录了创建一个Nancy框架的WebApi接口,这一章就在这个接口Demo上继续添加签名安全认证,保证接口的数据请求安全
一:创建一个MD5加密类,按照自己的加密方式来写
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Security; namespace Security { public class MD5 {
// 加密 public static string Encrypt(string str) { string result = string.Empty; string cl = DateTime.Now.Month + str + DateTime.Now.Day; var md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); byte[] data = md5.ComputeHash(Encoding.Default.GetBytes(cl)); data.Reverse(); for (int i = 0; i < data.Length; i++) { result += data[i].ToString("X"); } return result; } } }
二:创建接口授权密钥 (这里用配置类来代替,实际可以配置在数据库中)
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace NancyWebApiDemo.Security { public class LicenceConfig { private static Dictionary<string, string> Licences = new Dictionary<string, string>(); public LicenceConfig() { if (Licences.Count == 0) { Licences.Add("%%8795456$#@1198456451)(##@", "userOne"); //用户1的Api授权密钥 Licences.Add("$984351321515##&*135131133#", "userTwo"); //用户2的Api授权密钥 } } //获取拥有密钥系统用户 public string GetLicencesUser(string Key) { return Licences[Key]; } //检索密钥是否存在 public bool CheckExistLicence(string Key) { return Licences.ContainsKey(Key); } } }
创建一个缓存操作类。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Caching; namespace NancyWebApiDemo.Common { public class CacheHelper { /// <summary> /// 获取数据缓存 /// </summary> /// <param name="cacheKey">键</param> public static object GetCache(string cacheKey) { var objCache = HttpRuntime.Cache.Get(cacheKey); return objCache; } /// <summary> /// 设置数据缓存 /// </summary> public static void SetCache(string cacheKey, object objObject) { var objCache = HttpRuntime.Cache; objCache.Insert(cacheKey, objObject); } /// <summary> /// 设置数据缓存 /// </summary> public static void SetCache(string cacheKey, object objObject, int timeout = 7200) { try { if (objObject == null) return; var objCache = HttpRuntime.Cache; //过期时间 objCache.Insert(cacheKey, objObject, null, DateTime.Now.AddSeconds(timeout), TimeSpan.Zero, CacheItemPriority.High, null); } catch (Exception) { //throw; } } /// <summary> /// 移除指定数据缓存 /// </summary> public static void RemoveCache(string cacheKey) { var cache = HttpRuntime.Cache; cache.Remove(cacheKey); } /// <summary> /// 移除全部缓存 /// </summary> public static void RemoveAllCache() { var cache = HttpRuntime.Cache; var cacheEnum = cache.GetEnumerator(); while (cacheEnum.MoveNext()) { cache.Remove(cacheEnum.Key.ToString()); } } } }
三:在ApiModule.cs 创建签名获取接口
//获取Api签名 Post["/getSign"] = p => { CommResponse<object> response = new CommResponse<object>(); response.Code = CodeConfig.CodeFailed; try { string key = Request.Query["key"]; //获取 string data = Request.Query["data"];//请求的json数据 string type = Request.Query["type"]; //请求动作 bool flag = new Security.LicenceConfig().CheckExistLicence(key); if (flag) { //创建签名 switch (type) { case "Query": response.Message = "请求成功"; response.Code = CodeConfig.CodeSuccess; response.Data = Security.MD5.Encrypt(type + key + data); break; case "Write": response.Message = "请求成功"; response.Code = CodeConfig.CodeSuccess; response.Data = Security.MD5.Encrypt(type + key + data); break; default: response.Message = "接口操作类型错误"; break; } //获取签名成功 if (response.Code == CodeConfig.CodeSuccess) { //设置一个签名过期时间:120秒 CacheHelper.SetCache(response.Data as string, response.Data, 120); } } else { response.Message = "接口授权密钥不存在"; } } catch (Exception ex) { response.Message = ex.Message; } return Response.AsText(JsonHelper.ObjectConvertJson(response), "application/json"); };
接下来把项目运行起来 用Postman 工具测试下签名接口
传入正确的密钥
在这里已经拿到了签名,自己的程序应该马上跟着请求数据接口 查询或者写入数据,因为我们设置了签名的120秒有效期。
四:在ApiModule.cs 中创建一个签名认证方法
/// <summary> /// 验证签名 /// </summary> /// <param name="type">操作类型</param> /// <param name="data">请求的源数据</param> /// <param name="sign">签名</param> /// <returns></returns> public CommResponse<object> VerificationSign(string type, string key, string data, string sign) { CommResponse<object> response = new CommResponse<object>(); response.Code = CodeConfig.CodeFailed; //计算签名 string old = Security.MD5.Encrypt(type + key + data); if (old.Equals(sign)) { //继续判断签名是否过期 object _data = CacheHelper.GetCache(sign); if (_data == null) { response.Message = "签名已过有效期"; } else { response.Code = CodeConfig.CodeSuccess; response.Message = "签名校验成功"; } } else { response.Message = "签名校验未通过"; } return response; }
创建几个类 :请求类和响应类和实体类
/// <summary> /// 接口请求类 /// </summary> public class CommRequest<T> { //签名 public string Sign { get; set; } //授权Key public string Key { get; set; } //操作类型:Query、Write public string Type { get; set; } //查询对象 public T Data { get; set; } }
/// <summary> /// 接口响应类 /// </summary> public class CommResponse<T> { public int Code { get; set; } public string Message { get; set; } public T Data { get; set; } }
这个用户类我用来当查询条件和返回json
/// <summary> /// 用户类 /// </summary> public class UserInfo { public string ID { get; set; } public string Name { get; set; } public string Phone { get; set; } public string Address { get; set; } }
在ApiModule.cs中在定义一个初始化返回CommResponse的json方法
/// <summary> /// 初始化一个Commresponse的Json /// </summary> /// <param name="code">返回代码</param> /// <param name="msg">描述</param> /// <param name="data">数据</param> /// <returns></returns> public string InitReturnResponseJson(int code, string msg, object data = null) { CommResponse<object> response = new CommResponse<object>(); response.Code = code; response.Message = msg; response.Data = data; return JsonHelper.ObjectConvertJson(response); }
五:在正式的数据访问接口中 调用验证签名的方法
//查询方法 Post["queryUser"] = p => { string param = Request.Query["param"]; string json = Request.Query["json"]; string result = string.Empty; CommRequest<UserInfo> request = null; CommResponse<object> response; try { request = JsonHelper.JsonConvertObject<CommRequest<UserInfo>>(param); request.Data = JsonHelper.JsonConvertObject<UserInfo>(json); //验证签名 response = VerificationSign(request.Type, request.Key, json, request.Sign); if (response.Code == CodeConfig.CodeFailed) { return Response.AsText(JsonHelper.ObjectConvertJson(response), "application/json"); } } catch { result = InitReturnResponseJson(CodeConfig.CodeFailed, "Json参数格式错误"); return Response.AsText(result, "application/json"); } //进入接口,开始进行数据操作 //response = QueryUserInfo(request.Data.ID); //result = JsonHelper.ObjectConvertJson(response); //返回数据 response.Code = CodeConfig.CodeSuccess; response.Message = "请求成功"; response.Data= new { Id = request.Data.ID, Name = "Tom", Address = "四川省成都市" }; result = JsonHelper.ObjectConvertJson(response); return Response.AsText(result, "application/json"); };
六:测试查询接口
1.当输入错误的签名或者当发送的json查询参数被抓取后篡改 都是无法通过服务器签名验证的 (在调用此数据接口时,应先获取sign签名,见上面!!)
2.或者当签名正确,但签名已过设置的2分钟有效期。也是无法正常访问接口的
3.当参数完全正确和签名通过后 则可以拿到数据
接口请求安全大概就到这里,另外除此之外 还可以引用一些 限流框架,限制某个IP地址在规定时间内的访问次数。
C# Nancy框架开发 WebApi 二:接口安全签名认证
标签:convert ctc type oid dict int pre tco color
原文地址:https://www.cnblogs.com/Csharp-jd/p/12762273.html