文章目录
1 接口鉴权
鉴定是否有访问接口的权限。
1.1 cookie鉴权
cookie是服务器产生的,保存在浏览器(客户端)中,http协议是无连接,无状态的。
cookie通过键值对的方式来保存记录。
cookie原理
第一次访问服务器的时候,服务器会产生cookie,通过响应头的set-cookie将cookie发送给浏览器,cookie保存在浏览器中。在浏览器第2-n次请求时都会带上cookie信息。
cookie包括信息:name,value,domain,path,expries,seize。
cookie有回话级cookie和持久化cookie。
1.2 session鉴权
session是服务器产生的,保存在服务器的内存中。session可以使用cookie来访问,通过sessionid。
session原理
当登录的时候,服务器会产生session,session通过cookie把sessionid传给客户端,然后在后面所有的请求里面都会自动带上sessionid,该sessionid和服务器内存中的sessionid对比,哦按段是都是同一个客户端。保存在服务器的内存中的session失效时间为30分钟。
例如:tomcat服务器,在apache-tomcat-9.0.60\conf目录下的web.xml文件中,session-timeout标签对session失效时间进行调整,如下图所示:
sessionid传值方式有隐藏域,url和cookie,绝大数情况下使用cookie传递。
1.3 token鉴权
token是服务器产生的,保存在服务器的硬盘中。接口测试通过一个专门获取token的接口或者登录接口获取token,获取token之后每次请求其他接口都必须带上token。
cookie,session,token的相同点和不同点?
相同点:都是在服务器产生的,都是用于鉴权。
不同点:保存的地方不同,cookie保存在浏览器中,session保存在服务器的内存中,token保存在服务器的硬盘中。
cookie保存不安全,保存非重要的数据。
session保存重要数据。
token是独立的鉴权,与session和cookie无关。
1.4 Postman的鉴权方式
bearer token鉴权就是发送一个鉴权码(令牌)。在请求页面中的Authorization,选择Bearer Token,填入token值,如下图所示:
basic Auth鉴权,通过用户名和密码实现鉴权,如下图所示:
2 Mock Server
mock测试就是测试过程中,对于一些不容易创建或者不容易获取的比较复杂的对象,用一个模拟的对象去代替。
mock是为了解决单元之间的耦合依赖关系。(桩服务)
比如:工作中前后端分离,前端已经开发好了,但是后端的接口没有开发好,此时使用Mock Server模拟一个接口提供给前端使用。
首先,新建Mock,填写URL地址{{url}}/testmock
,响应信息为sucess,点击【Next】按钮,如下图所示:
为Mock server取testmock名,如下图所示:
新建完mock server,会有url地址,如下图所示:
新建完mock server,会自动生成testmock的环境,如下图所示:
新建完mock server,会自动生成testmock的集合,如下图所示:
新建完mock server,会自动生成testmock的请求,如下图所示:
在Body填充成功的提示词sucess
,如下图所示:
打开浏览器,输入mock server给的url地址https://0cefbc69-52ee-440e-aec6-14e003fc4b32.mock.pstmn.io
加上项目名testmock
,会出现接口测试成功提示词,如下图所示:
3 接口加解密
接口加密。接口测试当中把传输的数据加密成密文再传输。
接口解密。获取密文后把密文还源成原始数据。
3.1 加密方式
对称式(私钥加密)有DES,AES,Base64
非对称加密(双钥加密)有RSA。公钥和私钥。
只加密不解密有DM5,SHA1,SHA3等等。主流使用DM5和SHA系列。
加密工具如下网址
https://www.bejson.com/
3.2 Postman实现加密接口
脚本生成url地址和加密脚本。
编写脚本api_login.py
,运行结果如下:
一直开着api_login.py
服务端,新建请求,输入url地址,在Pre-request Script调用Postman自带的MD5加密方法,加密账号和密码,并且将账号admin和密码123设置Wie全局变量,如下图所示:
设置参数,因为账号和密码的值设置为全局变量,所以可以直接调用这两个参数,如下图所示:
查看运行结果,成功,如下图所示:
查看MD5加密之后的账号和密码,如下图所示:
4 接口签名sign(难点)
接口签名是接口鉴权的一种,更加安全。
4.1 接口签名的定义
接口签名就是使用appid,appsecret,nonce(流水号),timestamp(时间戳),以及其他的各种参数按照一定的规则(一般是ASCII排序)组成用来识别你的账号有没有访问api接口的权限的字符串,组成之后再进行加密,这个经过加密的字符串就是sign签名。
流水号(nonce)是一串10位以上的随机一组数字或者随机的一组字符串。数字+字符串(guid)。
timestamp一般10分钟之内有效。
4.2 接口签名的作用
大大提高接口的安全性。
防止接口鉴权码泄露。
防止接口数据被篡改。签名针对的是所有的请求数据,只要有一个数字被改动了,那么sign就发生变化,请求就会失败。
防止接口被重复提交,nonce是唯一的,并且只有10分钟之内有效。
4.3 接口签名的规则
接口签名的规则很多,但是大同小异。
第一步,获取到所有的参数包括params和body,把所有的参数的key按照ASCII升序排列。例如:
{a:2,c:1,b:3}改为{a:2,b:3,c:1}
第二步,把参数按照key=value的方式组合,多个参数用&
分开。例如:
a=2&b=3&c=1
第三步,用申请到的appid和appsecret拼接到参数的最前面。例如:
appid=123&appsecret=456&a=2&b=3&c=1
第四步,把订单号和时间戳拼接到参数的最后面。例如:
appid=123&appsecret=456&a=2&b=3&c=1&nonce=987654321×tamp=089769123
第五步,把上述字符串通过MD5加密,加密之后大写,形成sign。例如:
sign=123QWEIOUSDAFKDJHFSKJDFHWER3498756
第六步,把sign放在url或者是请求体或者请求头中发送给服务器做鉴权,经常是放在请求头中。
4.4 实战
在访问页面接口中获取csrf_token。在登录接口做接口签名。
4.4.1 访问页面接口
新建访问页面的接口,地址为http://47.107.116.139/phpwind/
,点击【Send】按钮,响应页面,如下图所示:
找到csrf_token的值,在Tests中使用正则提取csrf_token的值,并且设置为全局变量,如下图所示:
4.4.2 登录接口(实现sign)
要在网站先注册账号,才有账号和密码使用。
(1)请求地址为http://47.107.116.139/phpwind/index.php?m=u&c=login&a=dorun
(2)在Body填入账号、密码、token以及必要的参数,如下图所示:
(3)在请求头Headers填入必要的参数,如下图所示:
(4)在Pre-request Script中进行接口签名
第一,定义appid和appsecret,如下所示:
var appid = "test"
var appsecret = "123"
第二,定义函数,获得任意长度的随机数字,获取nonce,如下所示:
//定义函数,获得任意长度的随机数字,为nonce使用
function getnonce(min,max){
return Math.floor(Math.random() * (max - min +1)+min);
//获取nonce
var nonce = getnonce(1000000000,9999999999)
}
第三,获得时间戳,如下所示:
var timestamp = Date.now()
第四,获取Params中的参数,如下所示:
var params_args = pm.request.url.query.members
第五,获取Body中的参数,使用JSON.stringify()
将对象转换为字符串,如下所示:
var body_args = request.data;
console.log("body_args=" + JSON.stringify(body_args))
第六,将parmas和Body的参数组合,放在body_args
中,如下所示:
for(var i=0;i<params_args.length;i++){
body_args[params_args[i].key] = params_args[i].value;
}
console.log("params_body_args=" + JSON.stringify(body_args))
第七,把所有的参数的key按照ASCII码升序排序,需要定义按照key的ASCII码升序排序的函数,并调用该函数,如下所示:
//把所有的参数的key按照ASCII码升序排序
body_args = objectsort(body_args)
console.log("params_body_args=" + JSON.stringify(body_args))
//定义按照key的ASCII码升序排序的函数
function objectsort(obj){
var new_key = Object.keys(obj).sort();
console.log(new_key);
var arr = {};
for(var i =0;i<new_key.length;i++){
arr[new_key[i]] = obj[new_key[i]];
}
return arr;
}
第八,把字典格式的参数组合成key=value&key=value,如下所示:
var new_string=""
for(var j in body_args){
new_string += j + "=" + body_args[j] + "&"
}
console.log("new_string=" + JSON.stringify(new_string))
第九,在new_string的前面加上appid和appsecret,在new_string的后面加上nonce和timestamp,如下所示:
new_string ="appid=" + appid +"&" + "appsecret" + appsecret + "&" + new_string + "nonce=" + nonce + "&" +"timestamp=" + "&" + timestamp
第十,对new_string做MD5加密并大写,生成sign,sign保存为全局变量,如下所示:
var sign = CryptoJS.MD5("new_string").toString().toUpperCase();
console.log("sign="+sign)
pm.globals.set("sign", sign);
综上,在Pre-request Script代码如下:
//接口签名
//获取appid和appsecret
var appid = "test"
var appsecret = "123"
console.log("appid="+appid)
console.log("appsecret="+appsecret)
//获取nonce
var nonce = getnonce(1000000000,9999999999)
console.log("nonce=" + nonce)
//获得时间戳
var timestamp = Date.now()
console.log("timestamp=" + timestamp)
//获取params中的参数
var params_args = pm.request.url.query.members
console.log("params_args="+params_args)
//获取Body中的参数,JSON.parse()将字符串转换为对象,JSON.stringify()对象转换为字符串
var body_args = request.data;
console.log("body_args=" + JSON.stringify(body_args))
//parmas和Body的参数组合
for(var i=0;i<params_args.length;i++){
body_args[params_args[i].key] = params_args[i].value;
}
console.log("params_body_args=" + JSON.stringify(body_args))
//把所有的参数的key按照ASCII码升序排序
body_args = objectsort(body_args)
console.log("params_body_args=" + JSON.stringify(body_args))
//把字典格式的参数组合成key=value&key=value
var new_string=""
for(var j in body_args){
new_string += j + "=" + body_args[j] + "&"
}
console.log("new_string=" + JSON.stringify(new_string))
//在new_string的前面加上appid和appsecret,在new_string的后面加上nonce,timestamp
new_string ="appid=" + appid +"&" + "appsecret=" + appsecret + "&" + new_string + "nonce=" + nonce + "&" +"timestamp=" + "&" + timestamp
console.log(new_string)
//对new_string做MD5加密并大写,生成sign,sign保存为全局变量
var sign = CryptoJS.MD5("new_string").toString().toUpperCase();
console.log("sign="+sign)
pm.globals.set("sign", sign);
//---------------------------------------------------
//定义函数,获得任意长度的随机数字,为nonce使用
function getnonce(min,max){
return Math.floor(Math.random() * (max - min +1)+min);
}
//定义按照key的ASCII码升序排序的函数
function objectsort(obj){
var new_key = Object.keys(obj).sort();
console.log(new_key);
var arr = {};
for(var i =0;i<new_key.length;i++){
arr[new_key[i]] = obj[new_key[i]];
}
return arr;
}
点击【Send】按钮,在console窗口查看结果,如下图所示:
最后将sign放在请求头中,发送给服务器做鉴权,如下图所示:
小结
接口鉴权分为cookie鉴权、session鉴权、token鉴权。
大多数情况下使用token鉴权。
cookie,session,token的相同点和不同点?
相同点:都是在服务器产生的,都是用于鉴权。
不同点:保存的地方不同,cookie保存在浏览器中,session保存在服务器的内存中,token保存在服务器的硬盘中。
cookie保存不安全,保存非重要的数据。
session保存重要数据。
token是独立的鉴权,与session和cookie无关。
DM5和SHA系列是主流的加密方式。
==Mock Server==就是测试过程中,对于一些不容易创建或者不容易获取的比较复杂的对象,用一个模拟的对象去代替。
加密方式方式主要使用DM5加密和SHA系列。
接口签名sign规则(重点)
首先,定义appid,appsecret,nonce,timestamp。
然后,获取parmas和Body中的参数,并将两者组合成在一个字典中。
此外,根据字典的key的ASCII码升序排序,把字典格式转换为key=value&key=value形式,生成一个字符串。
在这个字符串前面加上appid和appsecret,后面加上nonce和timestamp。
对该字符串做MD5加密并大写,生成sign,sign保存为全局变量。
最后,把sign放在请求头中发送给服务器做鉴权。