一次开放接口从需求分析到发布sdk线上包
新年开场篇,欢迎来点赞;本篇和大家分享的是使用webapi做得接口服务验证框架,需求来源是我打算把上篇提到的图片验证码做成一种服务提供给大家,尽管我在上篇已经把代码打包开源了,但是如果有一种快速对接成功的服务,我想很多人也非常想使用吧,目前这服务已经上线并在nuget上发布有sdk客户端包(nuget包地址:Install-Package ShenNiuApi.SDK),值得庆幸的是仅上线一天就有46次的下载量(挺高兴的),兴许有感兴趣的朋友可以去nuget官网地址查看:神牛步行3的Nuget包;下面要分享的是在发布服务时候涉及到的验证调用方的架构,希望大家能够喜欢,也希望各位多多"扫码支持"和"推荐"谢谢(对了最近做了一个服装店地址:神牛衣柜3,希望需要买衣服鞋子的朋友多多捧场);
» 验证架构的需求分析 和 表结构的设计
» 使用webapi的ActionFilterAttribute做账号的统一验证
» ShenNiuApi.SDK客户端代码的分享
» 使用NuGet Package Explorer工具生成ShenNiuApi.SDK的nuget包并发布到nuget网站上
下面一步一个脚印的来分享:
» 验证架构的需求分析 和 表结构的设计
. 验证架构的需求分析
首先,对于一个接口服务来说通常会有一定的账号限制,必须要调用方使用符合规定并正确的账号传递给接口方才能调用成功接口,这里我们就以互联网行业一般接口验证的来制定我们的需求:
1. 接口验证需要:账号,密码,ip组,Token;通常密码需要加密,市面上加密方式很多如Md5,3des等加密方式;ip组顾名思义就是用来验证调用方请求的ip是否符合接口方新开账号时候绑定的指定ip,对于现今互联网行业来说分布式调用不是什么新鲜事了,所以这里需要的是ip组;Token一般都是由接口方制定的防篡改参数的保护措施,对于请求和接受双方需要有同样的Token值才能进行接口响应,通常需要有一个秘钥来促成加密;
2. 除了账号验证外有些需要接口需要按照调用次数来收取费用,因此我们这里有了次数限制的需求,但通常作为不同业务接口来说成本可能会高,尽管是同一个提供商提供的接口很有可能精细到每个接口的调用次数限制,所以我们这里设计就按照这种方式来的,真实业务具体看需求而定;
3. 通常我们对方开放接口时,会直接提供sdk客户端,方便调用方直接引用后直接可以调用方法不用再去管具体是什么请求协议啊或者调用接口方法不对等问题,这种提供sdk的方式直接只需要账号,密码,秘钥等就直接可以使用了,方便快捷而且在一定程度上避免了接口地址的暴露,可谓是好处多多;不好的第三就如同手机客户端,只要服务端更新了一些必要性的参数属性,那每次都需要调用方更新sdk包,不过这都不是事儿;
. 表结构的设计
有了上面的简要分析,咋们来看下数据库的表结构,这里主要用数据库来存储对应开通的接口账号,密码等信息和调用接口对应的次数:
表:MoApiUser(账号表) MoApiManager(接口方法表) MoApiRelation(账号与方法表关系表,其中包含有调用次数) MoLog(日志表)
表数据:
» 使用ActionFilterAttribute做账号的统一验证
有了上面需求和表的设计,下面我们来看下怎么使用Action的过滤器来统一做验证,在这之前我们需要了解下:为什么不弄一个父级的ApiController然后在里面做验证在来继承呢,而用Action过滤器来做呢,其实这两种方式都行,不过后者可以对那些不需要接口账号的接口做开放,容易控制;好了咋们一起看下Action过滤器里面着么做验证的,首先创建类 UserValidateAttribute 并继承 ActionFilterAttribute ,然后在给她一个属性ApiKeyId,这个属性用来传递调用方调用的接口编号(也就是对应接口的Id,这里对应数据库表MoApiManager中的ApiKeyId),这样做的目的是使用编号来方便数据库中做调用某个接口的统计,针对我们上面需求分析说的次数限制到某个接口上,而不是限制在账号上面(当然前者和必须和账号关联才行),因此我们定义一个这样的枚举方便对应接口中的数字:
/// <summary>
/// 接口与数据库关联编号
/// </summary>
public enum ApiKeyId
{ 文字验证码 = ,
图片验证码 = }
然后在过滤器中重新 public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) ,在OnActionExecuting中做非空验证,账号密码是否匹配,Token的验证,ip组的匹配,次数的对比,因此有了如下整体的自定义过滤器的代码:
public class UserValidateAttribute : ActionFilterAttribute
{ /// <summary>
/// 数据库与程序关联标号
/// </summary>
public MoEnumHelper.ApiKeyId ApiKeyId { get; set; } public UserValidateAttribute(MoEnumHelper.ApiKeyId apiKeyId)
{
this.ApiKeyId = apiKeyId;
} public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{ var response = new MoShenNiuBaseResponse();
var sbLog = new StringBuilder(string.Empty);
try
{ if (this.ApiKeyId <= ) { response.Msg = "接口暂未开通,请联系管理员"; return; }
sbLog.AppendFormat("当前服务:{0};", this.ApiKeyId); var request = actionContext.Request; #region 验证 #region 非空验证
if (actionContext.ActionArguments.Count <= ) { response.Msg = "请求格式不正确,请检查"; return; }
var moRequest = actionContext.ActionArguments["request"] as MoShenNiuBaseRequest; dynamic httpContext = actionContext.Request.Properties["MS_HttpContext"];
var userIp = httpContext.Request.UserHostAddress;
sbLog.AppendFormat("UserName:{0};Ip:{1};Token:{2};UserPwd:{3};", moRequest.UserName, userIp, moRequest.Token, moRequest.UserPwd.ToUpper());
if (string.IsNullOrWhiteSpace(moRequest.UserName) || string.IsNullOrWhiteSpace(moRequest.UserPwd))
{
response.Msg = "接口账号或密码不能为空";
return;
}
else if (string.IsNullOrWhiteSpace(moRequest.Token))
{
response.Msg = "Token不能为空";
return;
}
#endregion using (StageEntities db = new StageEntities())
{ #region 验证账号是否存在 var userInfo = db.MoApiUsers.Where(b => b.UserName.ToUpper() == moRequest.UserName.ToUpper() && b.UserPwd.ToUpper() == moRequest.UserPwd.ToUpper()).SingleOrDefault();
if (userInfo == null)
{
response.Msg = "接口账号或密码错误";
return;
}
#endregion #region 获取对应账号秘钥,验证token var newToken = Md5Extend.GetMd5Hash(string.Format("{0}_{1}_{2}",
moRequest.UserName.ToUpper(),
userInfo.TokenKey.ToUpper(),
moRequest.UserPwd.ToUpper())); sbLog.AppendFormat("服务器TokenKey:{0};Token:{1};", userInfo.TokenKey.ToUpper(), newToken); if (!moRequest.Token.Equals(newToken, StringComparison.OrdinalIgnoreCase))
{
response.Msg = "Token验证失败";
return;
}
#endregion #region 账号可用性
if (userInfo.Status != (int)MoEnumHelper.EmStatus.启用)
{
response.Msg = "接口账号暂被停用";
return;
}
else if (!string.IsNullOrWhiteSpace(userInfo.Ips))
{
if (!userInfo.Ips.Contains(userIp))
{
response.Msg = "接口ip无效";
return;
}
} var realationInfo = userInfo.MoApiRelations.Where(b => b.MoApiManager.ApiKeyId == (int)ApiKeyId && b.MoApiManager.Status == (int)MoEnumHelper.EmStatus.启用).SingleOrDefault();
if (realationInfo == null)
{
response.Msg = "接口暂未启用,请稍后重试";
return;
}
else if (realationInfo.MaxNum <= realationInfo.NowNum)
{
response.Msg = "接口调用次数已满,请联系管理员";
return;
}
#endregion //通过验证
response.Status = (int)MoEnumHelper.EmStatus.启用; #region 用户通过验证就增加次数 realationInfo.NowNum++;
var result = db.SaveChanges();
sbLog.AppendFormat("最大次数:{0};当前次数:{1};增加次数:{2};", realationInfo.MaxNum, realationInfo.NowNum, result);
#endregion
} #endregion }
catch (Exception ex)
{
response.Msg = "500接口处理请求异常,请稍后重试";
sbLog.AppendFormat("异常信息:{0};", ex.Message);
}
finally
{ sbLog.AppendFormat("返回Status:{0};Msg:{1};", response.Status, response.Msg);
//记录日志
StageClass._WrigLog(sbLog.ToString()); //验证失败返回
if (response.Status != (int)MoEnumHelper.EmStatus.启用 || !string.IsNullOrWhiteSpace(response.Msg))
{
actionContext.Response = new HttpResponseMessage()
{ StatusCode = System.Net.HttpStatusCode.OK,
Content = new StringContent(JsonConvert.SerializeObject(response))
};
}
}
}
}
代码中已经有了验证步骤模块的说明各位可以读一下,需要注意的地方是在Action过滤器中获取post传递给接口的对象参数方式是: var moRequest = actionContext.ActionArguments["request"] as MoShenNiuBaseRequest; 这样就能直接获取客户端传递过来的对象数据了;然后咋们再Controller代码中使用定义的过滤器,主要是在Action方法上方增加 [UserValidate(MoEnumHelper.ApiKeyId.文字验证码)]标记,通过MoEnumHelper.ApiKeyId.文字验证码来传递调用方调用的接口,这里我封装的接口是:文字验证码和图片验证码的接口,至于生成验证码的代码已经在上一篇MVC伪一个12306图片验证码已经开源出来了这里不多说,直接上整个webapi接口的Controller代码:
/// <summary>
/// ShenNiuApi - 接口
/// </summary>
[RoutePrefix("shenniuapi")]
public class ShenNiuController : ApiController
{ /// <summary>
/// 文字验证码
/// </summary>
/// <param name="request">验证码Request请求</param>
/// <returns>文字验证码图片流</returns>
[Route("WenZiValidateCode")]
[HttpPost]
[UserValidate(MoEnumHelper.ApiKeyId.文字验证码)]
public MoValidateCodeResponse GetWenZiValidateCode(MoValidateCodeRequest request)
{ var response = new MoValidateCodeResponse(); try
{
//返回的验证码文字
var code = string.Empty;
//图片流
response.CodeStream = ValidateCode.GetValidateCodeStream(ref code);
if (string.IsNullOrWhiteSpace(code) || response.CodeStream.Length <= ) { response.Msg = "获取验证码失败,请稍后重试"; return response; } response.Code = code;
response.Status = (int)MoEnumHelper.EmApiStatus.成功;
}
catch (Exception ex)
{
response.Msg = "获取验证码失败,请稍后重试";
} return response;
} /// <summary>
/// 图片验证码
/// </summary>
/// <param name="request">验证码Request请求</param>
/// <returns>图片验证码图片流及待验证图片坐标</returns>
[Route("TuPianValidateCode")]
[HttpPost]
[UserValidate(MoEnumHelper.ApiKeyId.图片验证码)]
public MoValidateCodeResponse GetTuPianValidateCode(MoValidateCodeRequest request)
{ var response = new MoValidateCodeResponse(); try
{
//获取图片类型
var validateCode = ValidateCode.GetInitImgCode();
if (validateCode == null || string.IsNullOrWhiteSpace(validateCode.IndexType)) { response.Msg = "获取验证码失败,请稍后重试"; return response; } //生成图片
var imgCode = new List<Stage.Com.Extend.MoImgCode>();
response.CodeStream = ValidateCode.CreateImgValidateStream(validateCode.IndexType, ref imgCode, strLen: );
if (imgCode.Count <= || response.CodeStream.Length <= || imgCode.Count <= ) { response.Msg = "获取验证码失败,请稍后重试"; return response; } //得到待匹配验证码坐标
foreach (var item in imgCode.Where(b=>b.IsChoice))
{
response.ImgCode.Add(new Stage.Model.MoImgCode()
{
ImgUrl = item.ImgUrl,
Index = item.Index,
IndexType = item.IndexType,
IsChoice = item.IsChoice,
Point_A = item.Point_A,
Point_B = item.Point_B
});
}
response.Code = validateCode.IndexType;
response.Status = (int)MoEnumHelper.EmApiStatus.成功;
}
catch (Exception ex)
{
response.Msg = "获取验证码失败,请稍后重试";
} return response;
} }
感觉是不是挺简单的,其实关键点在于过滤器中验证的步骤,要明白作为一个接口需要验证哪些东西这样才能保障接口的安全;
» ShenNiuApi.SDK客户端代码的分享
我们需求分析的时候也说了通过SDK的nuget方式提供给调用方使用,方便快捷,有一定的安全性;下面我们先来看下客户端所使用到的实体类:
namespace ShenNiuApi.SDK
{ /// <summary>
/// 神牛步行3枚举
/// </summary>
public class MoEnumHelper
{ public enum EmStatus
{
禁用 = ,
启用 =
}
} /// <summary>
/// 接口验证基类
/// </summary>
public class MoShenNiuBaseRequest
{
/// <summary>
/// 账号
/// </summary>
public string UserName { get; set; } /// <summary>
/// 密码
/// </summary>
public string UserPwd { get; set; } /// <summary>
/// 加密Token(方式:Md5(账号_秘钥_密码))
/// </summary>
public string Token { get; set; } } /// <summary>
/// 神牛接口返回基类
/// </summary>
public class MoShenNiuBaseResponse
{
/// <summary>
/// 返回状态: 0:失败 1:成功
/// </summary>
public int Status { get; set; } /// <summary>
/// 错误信息
/// </summary>
public string Msg { get; set; }
} /// <summary>
/// 验证码请求类
/// </summary>
public class MoValidateCodeRequest : MoShenNiuBaseRequest { } /// <summary>
/// 验证码返回类
/// </summary>
public class MoValidateCodeResponse : MoShenNiuBaseResponse
{ public MoValidateCodeResponse()
{
this.ImgCode = new List<MoImgCode>();
} /// <summary>
/// 验证码类型
/// </summary>
public string Code { get; set; } /// <summary>
/// 验证码图片流
/// </summary>
public byte[] CodeStream { get; set; } /// <summary>
/// 图片验证坐标
/// </summary>
public List<MoImgCode> ImgCode;
} /// <summary>
/// 图片验证码坐标
/// </summary>
public class MoImgCode
{
public string Index { get; set; } public string IndexType { get; set; } public string ImgUrl { get; set; } public Point Point_A { get; set; } public Point Point_B { get; set; } public bool IsChoice { get; set; }
} }
其中包含了账号实体,验证码请求实体和返回实体,挺简单的,因为这里接口目前只有两个嘛,当以后我不断开放接口后相信客户端的实体代码远不止于此;再来看方法,作为一个客户端肯定会有登陆账号,密码等传入的地方,我这里不是以配置文件传入的方式获取,而是直接通过客户端类构造函数来传递(构造函数上有默认参数是方便各位朋友使用接口的账号,如果有希望单独开放账号的合作伙伴可以联系我);客户端类中利用泛型T构造了一个统一的账号非空验证方法Validate和密码及Token构造的GetBaseRequest方法,对已代码:
/// <summary>
/// 得到基础请求格式
/// </summary>
/// <returns></returns>
private T GetBaseRequest<T>() where T : MoShenNiuBaseRequest, new()
{
var baseRequest = new T(); baseRequest.UserName = this.UserName;
baseRequest.UserPwd = Md5Extend.GetMd5Hash(this.UserPwd);
baseRequest.Token = Md5Extend.GetMd5Hash(string.Format("{0}_{1}_{2}",
this.UserName.ToUpper(),
this.TokenKey.ToUpper(),
baseRequest.UserPwd.ToUpper())); return baseRequest;
} /// <summary>
/// 非空验证
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
public void Validate<T>(T t)
where T : MoValidateCodeResponse
{
if (string.IsNullOrWhiteSpace(this.UserName) ||
string.IsNullOrWhiteSpace(this.UserPwd)) { t.Msg = "账号或密码不能为空"; }
else if (string.IsNullOrWhiteSpace(this.TokenKey))
{
t.Msg = "秘钥不能为空";
}
}
好了下面直接贴出对应的客户端中调用文字验证码和图片验证码的代码:
namespace ShenNiuApi.SDK
{
public class ShenNiuApiClient
{
#region 属性 public string ApiUrl { get; set; } /// <summary>
/// 账号
/// </summary>
public string UserName { get; set; } /// <summary>
/// 密码
/// </summary>
public string UserPwd { get; set; } /// <summary>
/// 秘钥
/// </summary>
public string TokenKey { get; set; }
#endregion public ShenNiuApiClient() { }
public ShenNiuApiClient(string userName = "神牛步行3", string userPwd = "", string tokenKey="代码改变世界,需求决定一切", string apiUrl = "http://www.lovexins.com:1001/shenniuapi")
{ this.UserName = userName;
this.UserPwd = userPwd;
this.TokenKey = tokenKey;
this.ApiUrl = apiUrl;
} /// <summary>
/// 得到基础请求格式
/// </summary>
/// <returns></returns>
private T GetBaseRequest<T>() where T : MoShenNiuBaseRequest, new()
{
var baseRequest = new T(); baseRequest.UserName = this.UserName;
baseRequest.UserPwd = Md5Extend.GetMd5Hash(this.UserPwd);
baseRequest.Token = Md5Extend.GetMd5Hash(string.Format("{0}_{1}_{2}",
this.UserName.ToUpper(),
this.TokenKey.ToUpper(),
baseRequest.UserPwd.ToUpper())); return baseRequest;
} /// <summary>
/// 非空验证
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
public void Validate<T>(T t)
where T : MoValidateCodeResponse
{
if (string.IsNullOrWhiteSpace(this.UserName) ||
string.IsNullOrWhiteSpace(this.UserPwd)) { t.Msg = "账号或密码不能为空"; }
else if (string.IsNullOrWhiteSpace(this.TokenKey))
{
t.Msg = "秘钥不能为空";
}
} /// <summary>
/// 获取文字验证码
/// </summary>
/// <returns></returns>
public async Task<MoValidateCodeResponse> GetWenZiValidateCodeAsync()
{ var response = new MoValidateCodeResponse();
try
{
//非空验证
Validate(response);
if (!string.IsNullOrWhiteSpace(response.Msg)) { return response; } //获取基础请求设置
var request = this.GetBaseRequest<MoValidateCodeRequest>(); //json化
var requestStr = JsonConvert.SerializeObject(request);
//发送请求
var returnStr = string.Empty;
using (HttpClient client = new HttpClient())
{
client.Timeout = TimeSpan.FromSeconds();
var stringContent = new StringContent(requestStr, Encoding.UTF8, "application/x-www-form-urlencoded");
stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var httpResponseMessage = client.PostAsync(this.ApiUrl + "/WenZiValidateCode", stringContent).Result;
var stream = await httpResponseMessage.Content.ReadAsStreamAsync();
using (StreamReader reader = new StreamReader(stream))
{
returnStr = await reader.ReadToEndAsync();
}
}
if (string.IsNullOrWhiteSpace(returnStr))
{ return response;
}
//解析
response = JsonConvert.DeserializeObject<MoValidateCodeResponse>(returnStr);
}
catch (Exception ex)
{
response.Msg = ex.Message;
}
return response;
} /// <summary>
/// 获取图片验证码
/// </summary>
/// <returns></returns>
public async Task<MoValidateCodeResponse> GetTuPianValidateCodeAsync()
{ var response = new MoValidateCodeResponse();
try
{
//非空验证
Validate(response);
if (!string.IsNullOrWhiteSpace(response.Msg)) { return response; } //获取基础请求设置
var request = this.GetBaseRequest<MoValidateCodeRequest>(); //json化
var requestStr = JsonConvert.SerializeObject(request);
//发送请求
var returnStr = string.Empty;
using (HttpClient client = new HttpClient())
{
client.Timeout = TimeSpan.FromSeconds();
var stringContent = new StringContent(requestStr, Encoding.UTF8, "application/x-www-form-urlencoded");
stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var httpResponseMessage = client.PostAsync(this.ApiUrl + "/TuPianValidateCode", stringContent).Result;
var stream = await httpResponseMessage.Content.ReadAsStreamAsync();
using (StreamReader reader = new StreamReader(stream))
{
returnStr = await reader.ReadToEndAsync();
}
}
if (string.IsNullOrWhiteSpace(returnStr))
{ return response;
}
//解析
response = JsonConvert.DeserializeObject<MoValidateCodeResponse>(returnStr);
}
catch (Exception ex)
{
response.Msg = ex.Message;
}
return response;
} }
}
» 使用NuGet Package Explorer工具生成ShenNiuApi.SDK的nuget包并发布到nuget网站上
因为我们要发布Sdk的nuget包,所以需要打包才行,这里就不用nuget命令了而是使用NuGet Package Explorer工具来打包,首先安装好工具后,我们打开有这样的画面:
我们选中如上图所示的选项,然后选中"编辑选项":
然后录入如下信息即可,您也可以录入更多的依赖等选项的信息:
这些信息是我发布的sdk,您们自己的可以不用填写这么详细哈哈,记得填完后再点击刚才位置的绿色钩钩(保存),好了接下来重点是在工具的右边的"Package Contents"区域=》右键鼠标=》选中如下图所示选项:
这里选项的意思添加类库dll,点击完后会有一个"Lib"出现,再右键Lib选中"Add .Net Folder"=》"V4.5"后面这个4.5是您打包项目的版本,我的是适用于4.5的,如下图:
然后再直接把您项目bin下面生成的dll(我这里是ShenNiuApi.SDK.dll)直接拖到"Package Contents"区域并且是在"V4.5"的下级,效果如下:
最后一步"保存"我们的nuget文件,先点击工具左上角的"File"=》"Save",有提示包文件保存在哪里,确定后就可以在您保存的文件夹下面看到您的nuget包了:
怎么样使用工具是不是很简单,您成功生成自己的nuget包了么;如果您想包您的包发布到nuget共全世界.net程序猿使用那么还是使用此工具“File”=》“publish”=》如图:
不错意外您的nuget包就发布上去了,并且在vs中通过搜索包也能看到,例如我这里的包:
如果能收到您自己的nuget包是不是感觉很兴奋呢哈哈,我也是当截图此刻发布两天的sdk已经有51次下载量了,不错啦;网站上的描述:
到此本章的内容就结束了,希望给您带来了学习的帮助,如果感谢我的话并且考虑要买双鞋子和衣服,不妨来小弟衣服店看看:神牛衣柜3,非常感谢您的支持,也感谢多多点赞。
代码资源包:使用ShenNiuApi.SDK的nuget包
一次开放接口从需求分析到发布sdk线上包的更多相关文章
- 研发流程 接口定义&开发&前后端联调 线上日志观察 模型变动
阿里等大厂的研发流程,进去前先了解一下_我们一起进大厂 - SegmentFault 思否 https://segmentfault.com/a/1190000021831640 接口定义 测试用例评 ...
- 直播预告 | 猪齿鱼V1.1发布,线上新功能详解邀您参加
2021年11月11日,数智化效能平台猪齿鱼 Choerodon发布 V1.1版本,多项功能新增或优化,多管齐下,全面提升团队工作效能! 通过提供体系化方法论和协作.测试.DevOps及容器工具,猪齿 ...
- Docker在Linux上运行NetCore系列(二)把本地编译好的镜像发布到线上阿里云仓库
转发请注明此文章作者与路径,请尊重原著,违者必究. 系列文章:https://www.cnblogs.com/alunchen/p/10121379.html 开始 本篇文章结束在本地创建完成镜像后, ...
- 第一周助教小结——发布作业&线上答疑
第一周助教小结 助教博客:https://www.cnblogs.com/jason5689/ 本周点评数目:0份 由于发布的作业还未截至,第一次的作业点评还没开始进行,就描述一下评论博客前的感受吧 ...
- TFS线上生成环境发布历程
继前文 TFS在项目中Devops落地进程(上) TFS在项目中DevOps落地进程(下) 自从之前将开发环境使用TFS进行了自动化之后,就享受在此成果中,其他后续进度就停顿了好一段时间. 毕竟在我们 ...
- 【转】App开放接口api安全性—Token签名sign的设计与实现
前言 在app开放接口api的设计中,避免不了的就是安全性问题,因为大多数接口涉及到用户的个人信息以及一些敏感的数据,所以对这些接口需要进行身份的认证,那么这就需要用户提供一些信息,比如用户名密码等, ...
- App开放接口api安全性的设计与实现
前言 在app开放接口api的设计中,避免不了的就是安全性问题,因为大多数接口涉及到用户的个人信息以及一些敏感的数据,所以对这些接口需要进行身份的认证, 那么这就需要用户提供一些信息,比如用户名密码等 ...
- App开放接口api安全性—Token签名sign的设计与实现
前言 在app开放接口api的设计中,避免不了的就是安全性问题,因为大多数接口涉及到用户的个人信息以及一些敏感的数据,所以对这些接口需要进行身份的认证,那么这就需要用户提供一些信息,比如用户名密码等, ...
- 开放接口/RESTful/Api服务的设计和安全方案详解
一.总体思路 这个涉及到两个方面问题:一个是接口访问认证问题,主要解决谁可以使用接口(用户登录验证.来路验证)一个是数据数据传输安全,主要解决接口数据被监听(HTTPS安全传输.敏感内容加密.数字签名 ...
随机推荐
- linux devel包 和 非devel包的区别
devel 包主要是供开发用,至少包括以下2个东西: 1. 头文件 2. 链接库 有的还含有开发文档或演示代码. 以 glib 和 glib-devel 为例: 如果你安装基于 glib 开发的程序, ...
- 如何实现简单的位数组(bit array)(转)
源:如何实现简单的位数组(bit array) 在 comp.lang.c 上面看到一则不错的 FAQ,<How can I implement sets or arrays of bits?& ...
- C语言实现求字符串子集问题
这个问题在于实现Apriori算法的时候需要求各个频繁集的关联规则,而这时需要在求得最大的频繁集中求各个频繁集的真子集.然后在实现这一步的时候被卡主了,第一反应是用递归完成,但是面对数据挖掘中庞大的项 ...
- HUST 1371 Emergency relief
状态压缩. 每一个人所需的物品对应一个数字,统计一个每个数字有几个.每一种提供物品的状态也对应一个数字,然后暴力判断. #include<cstdio> #include<cstri ...
- 51nod贪心算法教程
51nod确实是一个好oj,题目质量不错,wa了还放数据,学习算法来说挺好的,这次我做了几个水的贪心,虽然水,但是确实都很典型. 教程链接:http://www.51nod.com/tutorial/ ...
- salt自动化部署
1. 到编译机器编译 /export/Deploy/vm-agent 执行脚本 ./vm-agent.sh develop -alpha 2.检查rpm包是否打包成功 http://172.18.13 ...
- ubuntu12.04+fuerte 下跑通lsd-slam——使用usb摄像头
上一篇介绍了如何使用数据集跑lsd-slam,这篇介绍如何用一个普通的usb摄像头跑lsd-slam,默认ubuntu12.04,fuerte已经安装好,workspace也已设置,如果没有,请参考上 ...
- CSS实现导航条Tab切换的三种方法
前面的话 导航条Tab在页面中非常常见,本文说详细介绍CSS实现导航条Tab的三种方法 布局 根据上图所示,先规定几个定义,上图的模块整体叫做导航,由导航标题和导航内容组成.要实现上图所示的布 ...
- javascript中的元素包含判断
在实际开发中,很多时候需要知道某个节点是不是另一个节点的后代.很多浏览器提供了contains方法,如: console.log(document.documentElement.contains(d ...
- 手动写一个Servlet
一.做一个类,派生自HttpServlet 1.导两个包 javax.servlet.*; javax.servlet.http.* 2.重写两个方法doGet,doPost 打开tomcat中的se ...