原文地址:http://www.cnblogs.com/hubro/p/6248353.html

在各种手机APP泛滥的现在,背后都有同样泛滥的API接口在支撑,其中鱼龙混杂,直接裸奔的WEB API大量存在,安全性令人堪优

在以前WEB API概念没有很普及的时候,都采用自已定义的接口和结构,对于公开访问的接口,专业点的都会做下安全验证,数据签名之类

反而现在,谁都可以用WEB API估接口,安全性早忘一边了,特别是外包小公司的APP项目,80%都有安全漏洞(面试了大半年APP开发得出的结论)

特在过年之前,整理了下在用的解决方案,本方案解决了

  • 数据安全问题
  • 标准消息结构
  • 接口测试程序
  • 接口文档体现

正文

数据结构

对于一个接口,返回的内容除了要返回业务数据外,还得返回处理状态,并且这个状态是在每个接口都得有

所以数据格式都会定义为:

数据头(描述数据信息)

-----------------------------------

数据体(具体数据)

本文定义结构为

/// <summary>
/// 处理结果
/// </summary>
public class DealResult
{
/// <summary>
/// 处理结果
/// </summary>
public bool Result
{
get;
set;
}
/// <summary>
/// 消息
/// </summary>
public string Message
{
get;
set;
}
/// <summary>
/// 关联数据
/// </summary>
public object Data
{
get;
set;
}
}

  

所有接口都返回此对象,会描述本次请求的状态,和对应的数据,服务端则根据实际情况,返回处理结果和对应的数据

数据安全

开方式接口安全性就不用多说了,解决方法为加密,或数据签名验证,本文方案为进行数据签名

同返回的数据一样,提交到服务器的数据格式也统一约定,定义一个数据头基类

/// <summary>
/// 参数基类
/// </summary>
[Serializable]
public class ParameBase
{
string time = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
/// <summary>
/// 时间 格式 yyyy-MM-dd hh:mm:ss
/// </summary>
public string Time
{
get
{
return time;
}
set
{
time = value;
}
}
/// <summary>
/// 来源网站 = 1, IOS = 2,Android = 3, 微信 = 4
/// </summary>
public int SourceFrom
{
get;
set;
}
/// <summary>
/// 签名
/// </summary>
public string Token
{
get;
set;
} }

  一个登录对象表示为

/// <summary>
/// 登录
/// </summary>
public class Login : ParameBase
{
/// <summary>
/// 用户名
/// </summary>
public string Name
{
get;
set;
}
/// <summary>
/// 密码
/// </summary>
public string Password
{
get;
set;
}
}

  

数据签名表示为(KEY稍后讲到)

Token=MD5(属性值1+值2....+KEY)

按此对象表示为 MD5(Name+PassWord+Source+Time+KEY)

如果是GET参数怎么办,一样,按参数名计算,同时传递的参数要附带上Source,Time,Token

密钥机制

有的喜欢把密钥放在客户端,或固定密钥,显然都有安全问题,解决方法是动态获取

这就意味着在设计接口时,有一个接口是首先要调用的,让服务器返回密钥,于是就有了登录的概念

过程表示为

登录>返回用户信息和密钥=>存储用户信息和密钥=>使用密钥调用其它接口

这样只有登录者和服务器才知道自已的密钥了

综上所述,数据结构表示为

客户端提交结构为 ParameBase(附带签名信息)

服务端返回结构为 DealResult

登录机制

同网页请求一样,怎么知道多次调用是同一个人呢,这里采用了COOKIE的形式,登录后服务端返回一个COOKIE,客户端再请求时带上这个COOKIE

服务端需要存储这个COOKIE标识,所有的验证处理都会基于此标识来判断用户

有了上面基础,进入项目阶段

WEB API项目

其实用什么项目类型都行,只是WEB API方便了对象结构序列化和传参

默认WEB API路由RESUFUL形式,没有控制器方法,只能按METHOD来定义,很不方便,改成控制器的形式,这样就能用方法名来访问了

更改路由配置为

1
2
3
4
5
config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",//加上路由ACTION参数
                defaults: new { id = RouteParameter.Optional }
            );

在此文,数据分为请求和返回,以登录返回用户信息为例,登录为请求,用户信息为返回,示例对象结构为

用户对象

/// <summary>
/// 登录返回用户
/// </summary>
public class User
{
/// <summary>
/// 用户编号
/// </summary>
public int Id
{
get;
set;
}
/// <summary>
/// 名称
/// </summary>
public string Name
{
get;
set;
}
/// <summary>
/// 本次登录的KEY
/// </summary>
public string Key
{
get;
set;
}
/// <summary>
/// 本资登录的凭证
/// </summary>
public string Voucher
{
get;
set;
} }

请求方式

这里只采用了GET,POST两种方式,根据实际情况定义,控制器方法一定需要都标明,不然会出现路由BUG

定义登录方法

/// <summary>
/// 登录
/// </summary>
/// <param name="parame"></param>
/// <returns>User</returns>
[HttpPost]
[AnonymousSign]
public DealResult Login([FromBody] Login parame)
{
if (parame.Password != "")
{
return DealResult(false, "密码不正确");
}
string key2 = System.Guid.NewGuid().ToString();
string voucher = System.Guid.NewGuid().ToString();
var user = new User() { Name = parame.Name, Id = , Key = key2, Voucher = voucher };
var timeDiff = (DateTime.Now - Convert.ToDateTime(parame.Time)).TotalSeconds;//保存客户端和服务端时间差
LoginStatusContext.SetLoginStatus(voucher, user.Id, key2, timeDiff);
CoreHelper.CookieHelper.AddCookies("user", voucher);//存入COOKIE
return DealResult(true, "", user);
}

这里可以看到,创建了两个GUID,一个为用户凭证,一个为用户密钥,放入用户信息返回,同时调用LoginStatusContext.SetLoginStatus保存登录信息

同时使用了AnonymousSign标注,此方法使用默认签名Setting.DefaultKey

定义获取用信息方法

/// <summary>
/// 基本信息
/// </summary>
/// <param name="name">参数name</param>
/// <returns>User</returns>
[HttpGet]
public DealResult GetBasicInfo(string name)
{
var user = new User() { Name = name, Id = CurrentUserId };
return DealResult(true, string.Empty, user);
}

示例控制器完整定义

/// <summary>
/// 帐号操作
/// </summary>
[SignCheckAttribute]
public class AccountController : BaseController
{
/// <summary>
/// 登录
/// </summary>
/// <param name="parame"></param>
/// <returns>User</returns>
[HttpPost]
[AnonymousSign]
public DealResult Login([FromBody] Login parame)
{
if (parame.Password != "")
{
return DealResult(false, "密码不正确");
}
string key2 = System.Guid.NewGuid().ToString();
string voucher = System.Guid.NewGuid().ToString();
var user = new User() { Name = parame.Name, Id = , Key = key2, Voucher = voucher };
var timeDiff = (DateTime.Now - Convert.ToDateTime(parame.Time)).TotalSeconds;//保存客户端和服务端时间差
LoginStatusContext.SetLoginStatus(voucher, user.Id, key2, timeDiff);
CoreHelper.CookieHelper.AddCookies("user", voucher);//存入COOKIE
return DealResult(true, "", user);
} /// <summary>
/// 基本信息
/// </summary>
/// <param name="name">参数name</param>
/// <returns>User</returns>
[HttpGet]
public DealResult GetBasicInfo(string name)
{
var user = new User() { Name = name, Id = CurrentUserId };
return DealResult(true, string.Empty, user);
} /// <summary>
/// 测试异常
/// </summary>
/// <returns></returns>
[HttpGet]
public DealResult TestException()
{
int a = ;
var b = / a;
return DealResult(true);
} }

此控制器标注了SignCheckAttribute用以进行签名判断

具体实现可看SignCheckAttribute代码

SignCheckAttribute里实现了有

  • 数据签名判断
  • 签名超时判断
  • 用户登录限制
  • 签名重复使用处理(一个签名只能使用一次)
  • 过期登录用户处理(没有主动退出用户清理)

为了统一处理异常,配置了异常处理

1
GlobalConfiguration.Configuration.Filters.Add(new ExceptionAttribute());

对接口进行测试

大杀器来了,配合此方案放出了对应的测试工具,虽然WEB API有个扩展,但没法对此方案测试

使用此工具能方便按方案要求调用接口,为了方便参数拼接,POST和GET都采用URL参数的形式输入

测试登录/api/account/login

测试获取信息/api/account/GetBasicInfo

测试异常处理/api/account/TestException

在未登录情况下调用获取信息

接口文档

接口结构文档一直是很让人头疼的事,手写更改了又得维护,版本不一样还麻烦,自动生成最好了,同样WEB API 带扩展没法表示此结构详细

大杀器2号来了,按代码注释动态生成接口文档,文档格式与控制器保持一致

Home控制器代码实现

    public ActionResult Index(SummaryAnalysis.ExportType exportType = SummaryAnalysis.ExportType.NONE)
{
if (exportType != SummaryAnalysis.ExportType.NONE)
{
var str = SummaryAnalysis.Load(exportType);
return File(str, "application/octet-stream", "Model_" + exportType + ".zip");
}
else
{
if (string.IsNullOrEmpty(outPut))
{
outPut = SummaryAnalysis.Load(exportType);
}
ViewBag.OutPut = outPut;
return View();
}
}
}

在见过的开发文档,我觉得这是最好的展现形式了,还有锚点,快速定位到对象结构,并且与源代码保持一致

附WEB API 自带文档生成区别

附上项目源码

http://pan.baidu.com/s/1c2rDacK

项目结构:

----------WPF测试程序

----------接口示例

虽然跟CRL快速开发框架无关,但还是加上CRL的名,好文要顶!

【转】整套完整安全的API接口解决方案的更多相关文章

  1. 干货来袭-整套完整安全的API接口解决方案

    在各种手机APP泛滥的现在,背后都有同样泛滥的API接口在支撑,其中鱼龙混杂,直接裸奔的WEB API大量存在,安全性令人堪优 在以前WEB API概念没有很普及的时候,都采用自已定义的接口和结构,对 ...

  2. 安全的API接口解决方案

    在各种手机APP泛滥的现在,背后都有同样泛滥的API接口在支撑,其中鱼龙混杂,直接裸奔的WEB API大量存在,安全性令人堪优 在以前WEB API概念没有很普及的时候,都采用自已定义的接口和结构,对 ...

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

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

  4. 远程开户系统开放API接口

    如今随着智能识别技术的成熟和商用,金融领域也开始逐渐试水"远程开户".从OCR身份证识别到人脸识别,到如今市场上即将出现完整的远程开户系统,除了需要成熟的技术做支撑外,还需要对市场 ...

  5. List多个字段标识过滤 IIS发布.net core mvc web站点 ASP.NET Core 实战:构建带有版本控制的 API 接口 ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目 Using AutoFac

    List多个字段标识过滤 class Program{  public static void Main(string[] args) { List<T> list = new List& ...

  6. 快速录入快递地址API接口实现

    电商.ERP等行业下单环节极其重要,如何提高下单的效率已经成为首要问题.快速下单对于客户来说,为提前发货争取了时间:对于卖家来说,提高了库存周转率及利用率.快速下单的接口实现,需要解决如下几个问题:1 ...

  7. Web API接口设计(学习)

    1.在接口定义中确定MVC的GET或者POST方式 由于我们整个Web API平台是基于MVC的基础上进行的API开发,因此整个Web API的接口,在定义的时候,一般需要显示来声明接口是[HttpG ...

  8. 开放API接口安全处理

    一.开放API接口定义 顾名思义,开放出来给其他人调用的API接口就是开放API接口.例如,短信接口.邮件接口. 二.开放API的弱点 数据窃取 用户的密码等信息被不轨之人窃取,登录账号发布敏感信息, ...

  9. 亿级用户下的新浪微博平台架构 前端机(提供 API 接口服务),队列机(处理上行业务逻辑,主要是数据写入),存储(mc、mysql、mcq、redis 、HBase等)

    https://mp.weixin.qq.com/s/f319mm6QsetwxntvSXpKxg 亿级用户下的新浪微博平台架构 炼数成金前沿推荐 2014-12-04 序言 新浪微博在2014年3月 ...

随机推荐

  1. [bzoj3531][Sdoi2014][旅行] (主席树+树链剖分)

    Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. ...

  2. xtu summer individual 5 E - Burning Bridges

    Burning Bridges Time Limit: 5000ms Memory Limit: 32768KB This problem will be judged on ZJU. Origina ...

  3. Leetcode 153.寻找旋转数组中的最小值

    寻找旋转数组中的最小值 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 请找出其中最小的元素. ...

  4. ajax导出excel文件并增加等待动画效果

    html: <button class="btn btn-default" onclick="logToExcel('{:url('userLogToExcel', ...

  5. POJ-3041 Asteroids,二分匹配解决棋盘问题。

    Asteroids Time Limit: 1000MS   Memory Limit: 65536K       Description Bessie wants to navigate her s ...

  6. Django:(5)分页器 & forms组件

    Django组件:分页器 目录结构: urls.py from django.contrib import admin from django.urls import path from app01 ...

  7. msp430入门学习00

    在TI官网上找到MSP430的程序例程.数据手册.使用指南等文件.以MSP430F169为例,步骤如下: 1)进入ti官网:http://www.ti.com.cn/ 或者http://www.ti. ...

  8. CSU - 1115 最短的名字(字典树模板题)

    Description 在一个奇怪的村子中,很多人的名字都很长,比如aaaaa, bbb and abababab. 名字这么长,叫全名显然起来很不方便.所以村民之间一般只叫名字的前缀.比如叫'aaa ...

  9. POJ2586 Y2K Accounting Bug 解题报告

    Description Accounting for Computer Machinists (ACM) has sufferred from the Y2K bug and lost some vi ...

  10. Servlet的调试

    以下内容引用自http://wiki.jikexueyuan.com/project/servlet/debugging.html: 测试/调试Servlet始终是困难的.Servlets往往涉及大量 ...