接口测试 Jmeter 运行 Python 代码进行 AK/SK 认证 (使用 OS Process Sampler)

grizz · June 04, 2018 · Last by 萤烛 replied at July 16, 2019 · 23550 hits

一、 背景:

最近有个项目需要接口测试,接口都是通过aksk认证对请求进行加密签名,分享一下Jmeter解决方案。

二、 AK/SK:

AK/SK认证
通过API网关向下层服务发送请求时,必须使用AK(Access Key ID)、SK(Secret Access Key)对请求进行签名。

说明:
AK(Access Key ID):访问密钥ID。与私有访问密钥关联的唯一标识符;访问密钥ID和私有访问密钥一起使用,对请求进行加密签名。
SK(Secret Access Key):与访问密钥ID结合使用的密钥,对请求进行加密签名,可标识发送方,并防止请求被修改。

PS:对于AKSK大概知道怎么回事就OK,一般调用接口有如下两种认证方式,您可以任选其中一种进行认证鉴权。
Token认证:通过Token认证调用请求。
AK/SK认证:通过AK(Access Key ID)/SK(Secret Access Key)加密调用请求。AK/SK认证安全性更高。

Python实现aksk加密的代码如下(getAksk.py):

#encoding:utf-8

import requests
import hmac
import base64,sys
from hashlib import sha1

ak = "your-ak"
sk = "your-sk"

HOST = "127.0.0.1:5201"
METHOD = "POST"
PATH = "/getToken"
CONTENT_TYPE = "application/json"
data= '{"flag":"test","appId":"001"}'

def sign():
raw1 = "{} {}\n".format(METHOD, PATH)
raw2 = "Host: {}\n".format(HOST)
raw3 = "Content-Type: {}\n".format(CONTENT_TYPE)
raw4 = "\n"
print raw1
print raw2
print raw3
print raw4
print data
hmaccode = hmac.new(sk,"{}{}{}{}{}".format(raw1, raw2, raw3, raw4, data),sha1).digest()
b64code = base64.b64encode(hmaccode)
b64code = b64code.replace('/', '_').replace('+', '-')
print b64code
code = "mt {}:{}".format(ak,b64code)
print '"aksk":"{}"'.format(code)
return code

def main():
req = requests.Session()
headers = {
"Content-type": CONTENT_TYPE,
"Authorization": sign()
}
res = req.post("http://{}{}".format(HOST,PATH),data=data,headers=headers)
print headers
print res.content

if __name__ == "__main__":
main()

三、 实例:

假设我们的接口信息如下:

POST /getToken
Host: 127.0.0.1:5201
Content-Type: application/json
请求Body:{"flag":"test","appId":"001"}

我们发请求时需要在Headers中添加一个Authorization,Authorization的值是根据ak,sk和上面的四行信息生成的(参考代码中hmaccode的值如何生成),也就是说我们的请求URL和Body等是跟Authorization相关联的,如果我们抓包想改接口的Body,就必须把Headers的Authorization也相应修改,但是修改Authorization我们需要ak和sk的值,但是一般sk是不会暴露出来的。所以拿不到sk我们就无法发送跟请求body匹配的Authorization,接口请求就会因为授权失败而被服务器拒绝。

3.1、OS Process Sampler的使用

Jmeter调用Python代码我们会用到一个sampler:OS Process Sampler

OS Process Sampler:可以用来启动一个可执行程序,由于是通过命令行方式启动,所以我们可以用任何语言编写一个测试用的可执行程序(比如Linux的sh脚本)。在该可执行程序中调用我们的接口,并把返回的原始数据输出而交由JMeter做后续解析判断。

OS Process Sampler默认路径是jemter的bin目录,可在Working directory中定义当前工作目录,如果可执行文件有参数需要传入,在Command parameters中添加即可(后面会说到这个的使用),Timeout configuration中定义可执行文件的超时时间,单位(ms)。

3.2、OS Process Sampler调用sh脚本

我们编写一个getAksk.sh脚本,调用Python的getAksk.py文件:

pwd
python /Users/grizz/getAksk.py

执行结果:先输出工作目录,再执行py文件,执行getAksk.sh在jmeter中的输出如下:

其实就是在jmeter中打印出py文件的运行日志,Pycharm中的运行getAksk.py文件的输出如下,日志信息是一样的:

于是我们知道了,jmeter可以运行sh脚本,并把sh脚本的输出日志显示在jmeter的响应数据中,供jmeter进行解析调用。意思就是sh脚本能做的,jmeter就可以调着做,那jmeter调用Python代码就只是这个功能里面很少的一部分。网上对jmeter中OS Process Sampler的说明使用的资料很少,我开个调Python的头,大家可以根据业务需要自行扩展使用。
由于正则表达式提取器可以提取jmeter的输出,我们添加正则的配置如下:
正则表达式:"aksk":"(.+?)"

使用${aksk}即可使用Authorization的值mt your-ak:3j6UUc6x_dQhYgxlSX_AajCY1Yk=
然后在HTTP Header Manager中调用

/getToken接口请求时就会带上Authorization: mt your-ak:3j6UUc6x_dQhYgxlSX_AajCY1Yk=

3.3、OS Process Sampler参数化调用sh脚本

如果文章只说jmeter调Python代码,那可能已经写完了,因为jmeter可以调sh脚本,sh可以执行Python文件输出日志。但我们讲的是Jmeter运行Python代码进行AK/SK认证,上面的py文件中写死了接口的URL和Body,正常的我们不可能一个接口对应一个py文件,其实不同的接口,主要有两个参数是不一样的,那就是接口的URL和Body,于是我们考虑把这两个参数进行参数化。
但是我们的执行流程是jmeter调sh脚本,sh执行py文件,那么我们先要通过jmeter把接口的URL和Body传给sh脚本,sh脚本再把接口的URL和Body传给py文件去执行。
有些编程基础的同学应该知道,执行Python文件时可以接收参数,如
控制台执行:python /Users/grizz/getAksk.py /getToken {"flag":"test","appId":"001"}
传入参数请求URL/getToken和请求Body{"flag":"test","appId":"001"}给Python文件,Python使用 sys.argv可以接收传入的参数。

getAksk.py文件添加几行打印日志:

控制台输出如下:

我们可以看出当传入接口的URL和Body时:
sys.argv= ['getAksk.py', '/getToken', '{flag:test,appId:001}']
sys.argv就是将程序本身和给程序参数返回一个list,这个list中的索引为0的就是程序本身,list中的索引为1则为传入的第一个参数,依次类推。
明人不说暗话(我喜欢你),sh脚本运行时也支持传入参数。
getAksk.sh脚本文件改成:

pwd
python /Users/grizz/getAksk.py ${1} ${2}

运行:./getAksk.sh /getToken "{"flag":"test","appId":"001"}"

看样子我们只要把OS Process Sampler的Command由

/Users/grizz/jmeter/testcase/getAksk.sh
改成:
/Users/grizz/jmeter/testcase/getAksk.sh /getToken "{"flag":"test","appId":"001"}"

查看结果树种sampler的请求和响应数据:

显然报错了,我们的打开方式是错误的,哪里错了呢,是我们利用OS Process Sampler给sh脚本传参的方式错了,正确的打开方式如下:

再看看查看结果树中sampler的请求和响应数据

最后就只剩下一个问题了,HTTP请求sampler中的URL,Body和OS Process Sampler的Command parameter中一致,我尝试过对接口的请求body进行提取,但是我们需要改的是请求的headers,我们抓到请求Body时headers也确定了,于是只有把URL和Body放入文本中。
getAksk.csv文件(我设置成以?分隔读取):

/getToken?{"flag":"test","appId":"001"}

csvRead函数使用可参考:Jmeter 接口自动化-脚本数据分离实例

${DATA}=/Users/grizz/jmeter/testcase (getAksk.csv文件目录,可自行设置)

${__eval(${__CSVRead(${DATA}/getAksk.csv,0)})}= /getToken
${__eval(${__CSVRead(${DATA}/getAksk.csv,0)})}= {"flag":"test","appId":"001"}

OS Process Sampler设置

欢迎交流指正,感谢阅读。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 5 条回复 时间 点赞

Good!

挺好,赞一个。

Author only
grizz #4 · April 30, 2019 作者
小九 回复

windows是执行DOS命令,Mac可以执行shell命令,Windows没有执行shell命令的环境

谢谢楼主,解决了我的问题,我在win平台上做同样的事情,用bat代替了shell

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up