码迷,mamicode.com
首页 > Windows程序 > 详细

C# Nancy框架开发 WebApi 二:接口安全签名认证

时间:2020-04-23 17:33:47      阅读:96      评论:0      收藏:0      [点我收藏+]

标签: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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!