通过前几个教程的学习,对webapi的编写基本上就可以入门了,可以做项目了,今天我们再给接口加个参数签名认证,之前的接口相当于赤果果的暴露在了网络上,只要知道接口地址、接口调用方式和传参就可以畅所欲为的调用接口了,这给我们写的webapi带来了很大的安全隐患,所以这篇教程是给webapi加上一层保护措施,可能算不上最优解决方案,但起码能起到一定的保护措施。
保护思路
1.接口调用采用POST的方式,可以屏蔽一部分小白,增加接口调用的难度。
2.接口调用参数增加签名字段,一可以防止数据被篡改,二还可以防止其它人非法调用我们的接口。
接口签名算法
签名生成的通用步骤如下:
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意以下重要规则:
◆ 参数名ASCII码从小到大排序(字典序);
◆ 如果参数的值为空不参与签名;
◆ 参数名区分大小写;
◆ 验证调用返回或主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。
◆ key设置:将key设置在接口配置文件中,当key发生泄露时可第一时间通过修改配置文件来更改key值。
举例:
假设传送的参数如下:
a: aa
b: bb
c: cc
第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:
stringA="a=aa&b=bb&c=cc";
第二步:拼接API密钥:
stringSignTemp=stringA+"&key=afwfsfwexwegw" //注:key为用户在配置文件中自行设置的
sign=MD5(stringSignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7" //注:MD5签名方式
代码部分
第一步,在配置文件增加签名的key
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
//接口配置参数设置
"AppSettings": {
//数据库连接字符串
"xxxDB": "Server=ROBERT-PC\\SQLEXPRESS;User Id=xiaozhao;Password=xz123789;Database=XXX;",
//接口是否需要签名
"IsSign": "false",
//16位MD5签名key
"Md5Key": "5ShiCeShiAAAAAAA"
}
}
第二步,在Common增加SignMgr.cs类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XXX.Models;
namespace XXX.Common
{
/// <summary>
/// 签名管理
/// </summary>
public class SignMgr
{
/// <summary>
/// 验证用户请求参数
/// </summary>
/// <param name="p">参数中需要包含sign字段,用来验证签名是否正确</param>
/// <returns></returns>
public static bool ParamVerify(Object p)
{
//获取是否签名字段
string isSign = AppSettings.GetAppSeting("IsSign");
//获取MD5签名字段
string secretKey = AppSettings.GetAppSeting("Md5Key");
if (isSign == "false")
{
return true;
}
try
{
Type t = p.GetType();
var propertys = t.GetProperties();
string sign = "";
string temp = "";
var orderPropertys = propertys.OrderBy(p => p.Name); //ASCII码从小到大排序(字典序)
foreach (var item in orderPropertys)
{
string name = item.Name;
object oValue = item.GetValue(p);
string value = "";
if (oValue != null)//如果参数不为空则拼接参数
{
value = oValue.ToString();
//判断参数是否为sign,sign不参与签名
if (name != "sign")
{
temp += name + "=" + value + "&";
}
else
{
sign = value;
}
}
}
temp +="key=" +secretKey;
string md = Md5Encrypt.MD5(temp);
if (sign != "" && sign.ToUpper() == md.ToUpper())
{
//签名验证成功
return true;
}
else
{
//签名失败
return false;
}
}
catch (Exception ex)
{
//签名异常信息
return false;
}
}
}
}
第三步,验证
using System.Linq;
namespace XXX.Bo
{
public class UserBo
{
public static XXXContext db = new XXXContext();
/// <summary>
/// 增加一个用户数据
/// </summary>
/// <param name="model"></param>
public static Models.User.AddUserR AddUser(Models.User.AddUserP model)
{
var r = new Models.User.AddUserR();
if (Common.SignMgr.ParamVerify(model))//验证用户参数签名是否合法
{
Models.XXXEntities.User userSearch = (from u in db.User where u.Phone == model.phone select u).FirstOrDefault();
if (userSearch == null)
{
Models.XXXEntities.User user = new Models.XXXEntities.User();
user.Phone = model.phone;
user.Password = model.password;
user.NickName = model.nickName;
user.State = model.state;
db.User.Add(user);
int i = db.SaveChanges();
if (i > 0)
{
r.code = 1;
r.message = "数据插入成功";
}
else
{
r.code = 0;
r.message = "数据插入成功";
}
}
else
{
r.code = 0;
r.message = "手机号已经存在";
}
}
else
{
r.code = 0;
r.message = "签名失败";
}
return r;
}
}
}
完
项目已经上传github,看自行下载。
NetCore3.0-WebApi
求赞
创作不易,喜欢的请给个免费的赞吧!
网友评论