转自:https://www.cnblogs.com/wuhuacong/p/4620300.html#!comments

在上篇随笔《Web API应用架构设计分析(1)》,我对Web API的各种应用架构进行了概括性的分析和设计,Web API 是一种应用接口框架,它能够构建HTTP服务以支撑更广泛的客户端(包括浏览器,手机和平板电脑等移动设备)的框架,本篇继续这个主题,介绍如何利用ASP.NET Web API 来设计Web API层以及相关的调用处理。

1、Web API的接口访问分类

Web API接口的访问方式,大概可以分为几类:

1)一个是使用用户令牌,通过Web API接口进行数据访问。这种方式,可以有效识别用户的身份,为用户接口返回用户相关的数据,如包括用户信息维护、密码修改、或者用户联系人等与用户身份相关的数据。

2)一种是使用安全签名进行数据提交。这种方式提交的数据,URL连接的签名参数是经过安全一定规则的加密的,服务器收到数据后也经过同样规则的安全加密,确认数据没有被中途篡改后,再进行数据修改处理。因此我们可以为不同接入方式,如Web/APP/Winfrom等不同接入方式指定不同的加密秘钥,但是秘钥是双方约定的,并不在网络连接上传输,连接传输的一般是这个接入的AppID,服务器通过这个AppID来进行签名参数的加密对比,这种方式,类似微信后台的回调处理机制,它们就是经过这样的处理。

3)一种方式是提供公开的接口调用,不需要传入用户令牌、或者对参数进行加密签名的,这种接口一般较少,只是提供一些很常规的数据显示而已。

下面图示就是这几种接入方式的说明和大概应用场景。

2、Web API使用安全签名的实现

首先我们为用户注册的时候,需要由我们认可的终端发起,也就是它们需要进行安全签名,后台确认签名有效性,才能正常实现用户注册,否则遭到伪造数据,系统就失去原有的意义了。

    /// <summary>
/// 注册用户信息接口
/// </summary>
public interface IUserApi
{
/// <summary>
/// 注册用户处理,包括用户名,密码,身份证号,手机等信息
/// </summary>
/// <param name="json">注册用户信息</param>
/// <param name="signature">加密签名字符串</param>
/// <param name="timestamp">时间戳</param>
/// <param name="nonce">随机数</param>
/// <param name="appid">应用接入ID</param>
/// <returns></returns>
ResultData Add(UserJson json,
string signature, string timestamp, string nonce, string appid);
}

其实我们获得用户的令牌,也是需要进行用户安全签名认证的,这样我们才有效保证用户身份令牌获取的合法性。

    /// <summary>
/// 系统认证等基础接口
/// </summary>
public interface IAuthApi
{
/// <summary>
/// 注册用户获取访问令牌接口
/// </summary>
/// <param name="username">用户登录名称</param>
/// <param name="password">用户密码</param>
/// <param name="signature">加密签名字符串</param>
/// <param name="timestamp">时间戳</param>
/// <param name="nonce">随机数</param>
/// <param name="appid">应用接入ID</param>
/// <returns></returns>
TokenResult GetAccessToken(string username, string password,
string signature, string timestamp, string nonce, string appid);
}

上面介绍到的参数,我们提及了几个参数,一个是加密签名字符串,一个是时间戳,一个是随机数,一个是应用接入ID,我们一般的处理规则如下所示。

1)Web API 为各种应用接入,如APP、Web、Winform等接入端分配应用AppID以及通信密钥AppSecret,双方各自存储。
2)接入端在请求Web API接口时需携带以下参数:signature、 timestamp、nonce、appid,签名是根据几个参数和加密秘钥生成。
3) Web API 收到接口调用请求时需先检查传递的签名是否合法,验证后才调用相关接口。

加密签名在服务端(Web API端)的验证流程参考微信的接口的处理方式,处理逻辑如下所示。

1)检查timestamp 与系统时间是否相差在合理时间内,如10分钟。
2)将appSecret、timestamp、nonce三个参数进行字典序排序
3)将三个参数字符串拼接成一个字符串进行SHA1加密
4)加密后的字符串可与signature对比,若匹配则标识该次请求来源于某应用端,请求是合法的。

C#端代码校验如下所示。

        /// <summary>
/// 检查应用接入的数据完整性
/// </summary>
/// <param name="signature">加密签名内容</param>
/// <param name="timestamp">时间戳</param>
/// <param name="nonce">随机字符串</param>
/// <param name="appid">应用接入Id</param>
/// <returns></returns>
public CheckResult ValidateSignature(string signature, string timestamp, string nonce, string appid)
{
CheckResult result = new CheckResult();
result.errmsg = "数据完整性检查不通过"; //根据Appid获取接入渠道的详细信息
AppInfo channelInfo = BLLFactory<App>.Instance.FindByAppId(appid);
if (channelInfo != null)
{
#region 校验签名参数的来源是否正确
string[] ArrTmp = { channelInfo.AppSecret, timestamp, nonce }; Array.Sort(ArrTmp);
string tmpStr = string.Join("", ArrTmp); tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
tmpStr = tmpStr.ToLower(); if (tmpStr == signature && ValidateUtil.IsNumber(timestamp))
{
DateTime dtTime = timestamp.ToInt32().IntToDateTime();
double minutes = DateTime.Now.Subtract(dtTime).TotalMinutes;
if (minutes > timspanExpiredMinutes)
{
result.errmsg = "签名时间戳失效";
}
else
{
result.errmsg = "";
result.success = true;
result.channel = channelInfo.Channel;
}
}
#endregion
}
return result;
}

一旦我们完成对安全签名进行成功认证,也就是我们对数据提交的来源和完整性进行了确认,就可以进行更多和安全性相关的操作了,如获取用户的访问令牌信息的操作如下所示。

第一步是验证用户的签名是否符合要求,符合要求后进行用户信息的比对,并生成用户访问令牌数据JSON,返回给调用端即可。

3、Web API使用安全令牌的实现

通过上面的接口,我们获取到的用户访问令牌,以后和用户相关的信息调用,我们就可以通过这个令牌参数进行传递就可以了,这个令牌带有用户的一些基础信息,如用户ID,过期时间等等,这个Token的设计思路来源于JSON Web Token (JWT),具体可以参考http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html,以及GitHub上的项目https://github.com/jwt-dotnet/jwt

由于Web API的调用,都是一种无状态方式的调用方式,我们通过token来传递我们的用户信息,这样我们只需要验证Token就可以了。

JWT的令牌生成逻辑如下所示

令牌生成后,我们需要在Web API调用处理前,对令牌进行校验,确保令牌是正确有效的。

检查的代码,就是把令牌生成的过程逆反过来,获取相应的信息,并且对令牌签发的时间进行有效性判断,一般可以约定一个失效时间,如1天或者7天,也不用设置太短。

        /// <summary>
/// 检查用户的Token有效性
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public CheckResult ValidateToken(string token)
{
//返回的结果对象
CheckResult result = new CheckResult();
result.errmsg = "令牌检查不通过"; if (!string.IsNullOrEmpty(token))
{
try
{
string decodedJwt = JsonWebToken.Decode(token, sharedKey);
if (!string.IsNullOrEmpty(decodedJwt))
{
#region 检查令牌对象内容
dynamic root = JObject.Parse(decodedJwt);
string username = root.name;
string userid = root.iss;
int jwtcreated = (int)root.iat; //检查令牌的有效期,7天内有效
TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
int timestamp = (int)t.TotalDays;
if (timestamp - jwtcreated > expiredDays)
{
throw new ArgumentException("用户令牌失效.");
} //成功校验
result.success = true;
result.errmsg = "";
result.userid = userid;
#endregion
}
}
catch (Exception ex)
{
LogTextHelper.Error(ex);
}
}
return result;
}

一般来说,访问令牌不能永久有效,对于访问令牌的重新更新问题,可以设置一个规则,只允许最新的令牌使用,并把它存储在接口缓存里面进行对比,应用系统退出的时候,就把内存里面的Token移除就可以了。

4、ASP.NET Web API的开发

上面我们定义了一般的Web API接口,以及实现相应的业务实现,如果我们需要创建Web API层,还需要构建一个Web API项目的。

创建好相应的项目后,可以为项目添加一个Web API基类,方便控制共同的接口。

然后我们就可以在Controller目录上创建更多的应用API控制器了。

最后我们为了统一所有的API接口都是返回JSON方式,我们需要对WebApiConfig里面的代码进行设置下。

    public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API 配置和服务
config.SetCorsPolicyProviderFactory(new CorsPolicyFactory());
config.EnableCors(); // Web API 路由
config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "post", id = RouteParameter.Optional }
); // Remove the JSON formatter
//config.Formatters.Remove(config.Formatters.JsonFormatter); // Remove the XML formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);
}
}

5、Web API 接口的测试

接下来我们要做的就是需要增加业务接口,以便进行具体的测试了,建议使用Winform项目,对每个接口进行一个测试,或者也可以考虑使用单元测试的方式,看个人喜好吧。

例如我们如果要测试用户登陆的接口的话,我们的测试代码如下所示。

        /// <summary>
/// 生成签名字符串
/// </summary>
/// <param name="appSecret">接入秘钥</param>
/// <param name="timestamp">时间戳</param>
/// <param name="nonce">随机数</param>
private string SignatureString(string appSecret, string timestamp, string nonce)
{
string[] ArrTmp = { appSecret, timestamp, nonce }; Array.Sort(ArrTmp);
string tmpStr = string.Join("", ArrTmp); tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
return tmpStr.ToLower();
} private TokenResult GetTokenResult()
{
string timestamp = DateTime.Now.DateTimeToInt().ToString();
string nonce = new Random().NextDouble().ToString();
string signature = SignatureString(appSecret, timestamp, nonce); string appended = string.Format("&signature={0}&timestamp={1}&nonce={2}&appid={3}", signature, timestamp, nonce, appId);
string queryUrl = url + "Auth/GetAccessToken?username=test&password=123456" + appended; HttpHelper helper = new HttpHelper();
string token = helper.GetHtml(queryUrl);
Console.WriteLine(token);
TokenResult tokenResult = JsonConvert.DeserializeObject<TokenResult>(token);
return tokenResult;
}

如果我们已经获得了令牌,我们根据令牌传递参数给连接,并获取其他数据的测试处理代码如下所示。

            //获取访问令牌
TokenResult tokenResult = GetTokenResult(); string queryUrl = url + "/Contact/get?token=" + tokenResult.access_token;
HttpHelper helper = new HttpHelper();
string result = helper.GetHtml(queryUrl);
Console.WriteLine(result);

如果需要POST数据的话,那么调用代码如下所示。

            //使用POST方式
var data = new
{
name = "张三",
certno = "123456789",
};
var postData = data.ToJson(); queryUrl = url + "/Contact/Add?token=" + tokenResult.access_token;
helper = new HttpHelper();
helper.ContentType = "application/json";
result = helper.GetHtml(queryUrl, postData, true);
Console.WriteLine(result);

Web API后台,会自动把POST的JSON数据转换为对应的对象的。

如果是GET方式,我们可能可以直接通过浏览器进行调试,如果是POST方式,我们需要使用一些协助工具,如Fiddler等处理工具,但是最好的方式是自己根据需要弄一个测试工具,方便测试。

以下就是我为了自己Web API 接口开发的需要,专门弄的一个调试工具,可以自动组装相关的参数,包括使用安全签名的参数,还可以把所有参数数据进行存储。

Web API接口 安全验证的更多相关文章

  1. Winform混合式开发框架访问Web API接口的处理

    在我的混合式开发框架里面,集成了WebAPI的访问,这种访问方式不仅可以实现简便的数据交换,而且可以在多种平台上进行接入,如Winform程序.Web网站.移动端APP等多种接入方式,Web API的 ...

  2. K/3 Cloud Web API接口说明文

    K/3 Cloud Web API接口说明文 目的 三方集成,提供第三方系统与Cloud集成调用接口. 技术实现 HTTP + Json 提供标准接口 编号 名称 说明 1 Kingdee.BOS.W ...

  3. 初识web API接口及Restful接口规范

    一.web API接口 什么是web API接口?: 明确了请求方式,提供对应后台所需参数,请求url链接可以得到后台的响应数据 url : 返回数据的url https://api.map.baid ...

  4. ASP.NET Web API 接口执行时间监控

    软件产品常常会出现这样的情况:产品性能因某些无法预料的瓶颈而受到干扰,导致程序的处理效率降低,性能得不到充分的发挥.如何快速有效地找到软件产品的性能瓶颈,则是我们感兴趣的内容之一. 在本文中,我将解释 ...

  5. Web API接口之FileReader

    Web API接口之FileReader *:first-child { margin-top: 0 !important; } body>*:last-child { margin-botto ...

  6. 不使用jQuery对Web API接口POST,PUT,DELETE数据

    前些天,Insus.NET有演示Web API接口的操作: <怎样操作WebAPI接口(显示数据)>http://www.cnblogs.com/insus/p/5670401.html ...

  7. WebApi系列~通过HttpClient来调用Web Api接口~续~实体参数的传递

    回到目录 上一讲中介绍了使用HttpClient如何去调用一个标准的Web Api接口,并且我们知道了Post,Put方法只能有一个FromBody参数,再有多个参数时,上讲提到,需要将它封装成一个对 ...

  8. Web API接口设计经验总结

    在Web API接口的开发过程中,我们可能会碰到各种各样的问题,我在前面两篇随笔<Web API应用架构在Winform混合框架中的应用(1)>.<Web API应用架构在Winfo ...

  9. Web API 接口

    Web API 接口 在给网站编写 JavaScript 代码时,也有很多可用的 API.您可以使用下面的接口(也称为对象的类型)列表,开发 Web 应用程序或网站. 关于包含这些接口的 API 列表 ...

随机推荐

  1. jQgrid问题总结

    最近一段时间一直在使用jqgrid这个免费的插件,网上的资料也比较多.比较全,但是这里还是整理几个自己在开发过程中遇到的小问题. 1.自动换行 一行数据过多需要自动根据内容换行时,如果遇到在表格中的汉 ...

  2. .woff 文件404,配置到web.config

    <staticContent>        <remove fileExtension=".woff" />        <mimeMap fil ...

  3. bzoj4511: [Usaco2016 Jan]Subsequences Summing to Sevens

    前缀和. 设f[i]为前缀和%7=i的第一个点.那么答案就是max(i-f[s[i]%7])了. #include<cstdio> #include<algorithm> #i ...

  4. UVa 1606 (极角排序) Amphiphilic Carbon Molecules

    如果,没有紫书上的翻译的话,我觉得我可能读不懂这道题.=_=|| 题意: 平面上有n个点,不是白点就是黑点.现在要放一条直线,使得直线一侧的白点与另一侧的黑点加起来数目最多.直线上的点可以看作位于直线 ...

  5. 银行卡luhm校验算法

    /** * 15位银行卡luhm校验算法 * 1.从卡号最后一位数字开始,逆向将奇数位(1.3.5等等)相加. * 2.从卡号最后一位数字开始,逆向将偶数位数字,先乘以2(如果乘积为两位数,则将其减去 ...

  6. Java [leetcode 10] Regular Expression Matching

    问题描述: Implement regular expression matching with support for '.' and '*'. '.' Matches any single cha ...

  7. ARM Linux系统的时钟机制

    1. Linux下有两类时钟: 1.1 实时钟RTC 它由板上电池驱动的“Real Time Clock”也叫做RTC或者叫CMOS时钟,硬件时钟.当操作系统关机的时候,用这个来记录时间,但是对于运行 ...

  8. UVA 10510 Cactus

    题意:给出一个有向图,问是不是仙人掌图.仙人掌图:每个边只在一个普通环内的强连通图. 解法:tarjan判断强连通分量是否为1个,记录找环的路径,在每找到一个环时遍历路径记录点出现的次数,如果出现有点 ...

  9. 一个HR给应届毕业生的面试建议 后悔看到的太晚了 (转)

      开始之前务必记住: 黄金法则:80/20---你要承担起80%的谈话而面试官只会说20%.      白金法则:你必须试着控制面试的节奏和话题.      钻石法则:对于没有把握的问题,抛回给面试 ...

  10. ubuntu 中文界面下中文文件夹改英文

    首先,打开终端,切换成英文环境, export LANG=en_US   接着,目录转换 xdg-user-dirs-gtk-update   最后,切换回中文环境 export LANG=zh_CN ...