RSA Demo & Postman Scrpits
RSA Demo & Postman Scrpits
RSA Demo没什么好说的,这里其实重点是想说一下Postman提供的Scripts脚本(包括Pre-request Scripts和Tests Scripts)
RSA Demo
直接参看RSA Demo
Postman Scrpits
Postman提供了Scripts脚本,用来在request提交前和提交后对request和response进行处理
- Pre-request Scripts: 提交前对request进行处理,详细的描述可参看Pre-request Scripts
- Tests Scripts: 结果返回后对response进行处理,主要用来进行test测试,详细的描述可参看Tests Scripts
本次结合RSA的Demo,使用Postman来进行接口测试。
Postman有native app版本,也有chrome的插件版。Postman的scripts运行环境实际上是提供了个sandbox,来运行js脚本的。在sandbox环境中,Postman会注入一些工具类,参看Postman Sandbox
但这些工具类的使用是依赖于Sandbox环境的。
- Postman native: 提供了类似node的独立环境,无法获得window和navigator属性
- Postman chrome app: 提供了浏览器环境,可以获取window和navigator属性
上述区别导致了在引入第三方js插件时,两个环境的scripts脚本存在无法通用的可能,这个在本次RSA Demo的测试中,着实被坑了一把。
- jsencrypt: 无法在Postman native下使用,因为其向window注入了方法,并直接使用;在Postman chrome app下,通过修改tester_sandbox.html,加入引用的库和方法,可以使用。
- jsrsasign: 可以在Postman native下使用,但需要主动提供window和navigator对象,否则依然报错。
这里提供了jsrsasign在Postman native下的使用代码。
Postman native
话不多说,直接上代码。
注:代码同时提供了对lodash和CryptoJS的使用。
在Postman的native下,lodash需要使用require方式引入,而jquery已经不提倡使用了,至少我还没有找到合适的方式把jquery引入,因为eval方式报错了;
但在Postman的chrome app下(已经不提倡使用插件版本的Postman了),lodash以_
方式提供,已在window对象下,无需手动引入。而和jquery也以$
的方式在window对象下存在,同样无需手动引入。
Pre-request Scripts
var md5Password = CryptoJS.MD5("123").toString().toUpperCase();
console.log(md5Password);
var te = [1, 2, 3, 4];
var _ = require('lodash');
var de = _.reverse(te);
console.log(de);
window = {};
navigator = {};
pm.sendRequest({
url: 'http://localhost:8080/rsa/rest/api/v1/init',
method: "POST",
}, function (err, res) {
console.log(res.json());
console.log('-------------------- 华丽的分割线 请求前 -----------------------');
pm.sendRequest({
url: 'https://cdn.bootcss.com/jsrsasign/8.0.5/jsrsasign-all-min.js',
method: "GET",
}, function (err, res) {
var CLIENT_PUBLICKEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCPrkLZe1AxVnhckFoF/c5BbuW86/LQE5hSynrGq2Dho9SaGqEu8QpZfhqk+w6OQaM8cdiAbakty7sjRzJ47JlGzoxHlurYKfxvo1T/3N2gXFa4H0ZpZXlG+uetyTMl06ndFl9Ji9GvxVzWW2B/RRB5tsEEkdoET3AG4V5bh1VgrQIDAQAB";
var CLIENT_PRIVATEKEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAI+uQtl7UDFWeFyQWgX9zkFu5bzr8tATmFLKesarYOGj1JoaoS7xCll+GqT7Do5Bozxx2IBtqS3LuyNHMnjsmUbOjEeW6tgp/G+jVP/c3aBcVrgfRmlleUb6563JMyXTqd0WX0mL0a/FXNZbYH9FEHm2wQSR2gRPcAbhXluHVWCtAgMBAAECgYBBfyukHk1xIDzf3UHcZ1WFiHsbwuc+KSCP5RNQy0DvuxIoaak+T8zq/MxCltuMx6kU3cTWzqaHZM7bBxKgAyLfamrTcFyh4rUrkMzcBEENFkRng7//Px7vzwcUocygA4KGh6eGkef6/33yhgF4wUofUWgW2qyDNQm24OitLti7oQJBAPjOijg1gl6ytRrwdqPq+S4t7Y3ZHFjiis+7yhgZMZoS2JFeVtaQbbPfXzQ4eMExGEH2/lbOuMrsrEkxRUUNGfUCQQCT1apsFYDZwIcGSQ6DStEj4X+ukw5h/q2VnfI8B2u4EqbBbpzZ5DL7lo4yDDH85xifmLl0P3SrhSDeOSa/9ODZAkEA155OZHXi3GRs1MLNXjK07VM6CnK7wT/aYjpw4j97H/XzHs+t29Zga8BJhjzmUS5Vwlzlf584wAspJ2j+id/XvQJARDWLYj8xqkaYhh/jIFS+1k1O+h9DvZciRCwR/fx2iQGiCxGcMTSHCWnXxeO2lLeTtt9ige5dSF4uYhoAdQTpUQJBANoP3JGufyUusSp7UiRX/kUg1K2rfkrzg5MLNpPuKljs3mI/xGopddBogFNomZCbssGpUM+VFvNwnhZQByx58O4=";
var SERVER_PUBLICKEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsrxY7zwnU8/u9a5KClEjEHDiGyMXYBJUr+il5Pw9KsVqFuhydjV7EiMBTykQ4XuZdaBWqlA7KMOio9xsL8nuMZOSu3fsmuSvMjt6gX/7kd3TQO2Tbjs8sFokJ3LPYqrhWhHCxFe52USMiKEanKbSZch1uPF1+pQHfV4zo8Mu6FQIDAQAB";
var SERVER_PRIVATEKEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKyvFjvPCdTz+71rkoKUSMQcOIbIxdgElSv6KXk/D0qxWoW6HJ2NXsSIwFPKRDhe5l1oFaqUDsow6Kj3Gwvye4xk5K7d+ya5K8yO3qBf/uR3dNA7ZNuOzywWiQncs9iquFaEcLEV7nZRIyIoRqcptJlyHW48XX6lAd9XjOjwy7oVAgMBAAECgYEAk2mb506kq//j5R3RolsHizI0Jwt5qSCwXyxc/z4PxcmE5yerievG/Kto056VgjGxIgfahxWBUqVR1/uqQRas1A2j5/de8Y+LcpNrEuwF8YgOWmK3EAty0pgHQ1ezYSaxJ2AMBF427UrzMpGrB77UEzGE07GxbbC/sK/u66h0A/kCQQD89Q3OmWV8Gxie8XkWHeiUhseo3kZ9AYy7tRpsEkTkkWZAK2znphdHl35yDk0Cqu4uCe3usz6TfRlWu+3WK5k3AkEArsLXtUUt1IVeM0Z0Oxz8AWMb4v1lJiS4BhotZs7fyZ6DnMd+LIdfqQCLl9j3hCzdxEqIqmcuL2uGy1OYdfz9EwJAF+lGM9hWOoQJMMUcsBWFrbyL1Q+l1B04Y2n8JGkZsA16f+ha9A7ENpVAc6Gcb/seZqWzoxO4f5KcuZEsK0mVwwJAIp4qCJhZib2ZeWK9Z3BIYyX0wjQbs0CWy26oC7NzFQc3XvkNf1iZlGqtPDkYXrBchaOWCttBhNcx7ljy3HxuzQJAQxcxqCOUmLJah+Mtjb+aJQ2L6Lg3mBA62WNGxXDzpX2pAcJVZ7bNcsBq41rOpQEtQ8bEyj/Nfxxsxy/F57xuCQ==";
var jsrsasign = res.stream.toString();
// 执行jsrsasig,加载第三方库
eval(jsrsasign);
// RSAKey的扩展函数
RSAKey.prototype.getPEM = function(key, pemHeader) {
return hextopem(b64nltohex(key), pemHeader);
};
RSAKey.prototype.encryptB64 = function (text) {
return hextob64(this.encrypt(text));
};
RSAKey.prototype.decryptB64 = function (text) {
return this.decrypt(b64tohex(text));
};
RSAKey.prototype.getPrivateBaseKey = function () {
var keyPem = KEYUTIL.getPEM(this, "PKCS8PRV");
return pemtohex(keyPem);
};
RSAKey.prototype.getPrivateBaseKeyB64 = function () {
return hextob64(this.getPrivateBaseKey());
};
RSAKey.prototype.getPublicBaseKey = function () {
var keyPem = KEYUTIL.getPEM(this, "PKCS8PUB");
return pemtohex(keyPem);
};
RSAKey.prototype.getPublicBaseKeyB64 = function () {
return hextob64(this.getPublicBaseKey());
};
RSAKey.prototype.readPKCS8PrvKeyFromB64 = function (prvKeyB64) {
var prvKeyPem = this.getPEM(prvKeyB64, "PRIVATE KEY");
this.readPKCS8PrvKeyHex(pemtohex(prvKeyPem));
};
RSAKey.prototype.readPKCS8PubKeyFromB64 = function (pubKeyB64) {
var pubKeyPem = this.getPEM(pubKeyB64, "PUBLIC KEY");
this.readPKCS8PubKeyHex(pemtohex(pubKeyPem));
};
RSAKey.readPKCS9KeypairFromB64 = function(prvKeyB64, pubKeyB64) {
var prvKey = new RSAKey();
prvKey.readPKCS8PrvKeyFromB64(prvKeyB64);
var pubKey = new RSAKey();
pubKey.readPKCS8PubKeyFromB64(pubKeyB64);
var result = {};
result.prvKeyObj = prvKey;
result.pubKeyObj = pubKey;
return result;
};
/**
* 加密
* @param text 待加密的字符串
* @param key 加密的key
* @param isPub 是否使用publicKey加密,默认false
* @returns {*}
*/
function encrypt(text, key, isPub) {
// Encrypt with key...
var rsa = new RSAKey();
if(isPub) {
rsa.readPKCS8PubKeyFromB64(key);
} else {
rsa.readPKCS8PrvKeyFromB64(key);
}
var encrypted = rsa.encryptB64(text);
return encrypted;
}
/**
* 解密
* @param text 待解密的字符串
* @param key 解密的key
* @param isPub 是否使用publicKey解密,默认false
* @returns {*}
*/
function decrypt(text, key, isPub) {
// Decrypt with key...
var rsa = new RSAKey();
if(isPub) {
rsa.readPKCS8PubKeyFromB64(key);
} else {
rsa.readPKCS8PrvKeyFromB64(key);
}
var decrypted = rsa.decryptB64(text);
return decrypted;
}
var sPub = new RSAKey();
sPub.readPKCS8PubKeyFromB64(SERVER_PUBLICKEY);
var message = 'Java中文';
var encryptMessage = encrypt(message, sPub.getPublicBaseKeyB64(), true);
console.log('密文:', encryptMessage);
postman.setGlobalVariable('encryptMessage', encryptMessage);
postman.setGlobalVariable('cPub', CLIENT_PUBLICKEY);
});
});
Tests Scripts
window = {};
navigator = {};
pm.test("response is ok", function () {
console.log('-------------------- 华丽的分割线 请求后 -----------------------');
pm.response.to.have.status(200);
pm.sendRequest({
url: 'https://cdn.bootcss.com/jsrsasign/8.0.5/jsrsasign-all-min.js',
method: "GET",
}, function (err, res) {
var CLIENT_PUBLICKEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCPrkLZe1AxVnhckFoF/c5BbuW86/LQE5hSynrGq2Dho9SaGqEu8QpZfhqk+w6OQaM8cdiAbakty7sjRzJ47JlGzoxHlurYKfxvo1T/3N2gXFa4H0ZpZXlG+uetyTMl06ndFl9Ji9GvxVzWW2B/RRB5tsEEkdoET3AG4V5bh1VgrQIDAQAB";
var CLIENT_PRIVATEKEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAI+uQtl7UDFWeFyQWgX9zkFu5bzr8tATmFLKesarYOGj1JoaoS7xCll+GqT7Do5Bozxx2IBtqS3LuyNHMnjsmUbOjEeW6tgp/G+jVP/c3aBcVrgfRmlleUb6563JMyXTqd0WX0mL0a/FXNZbYH9FEHm2wQSR2gRPcAbhXluHVWCtAgMBAAECgYBBfyukHk1xIDzf3UHcZ1WFiHsbwuc+KSCP5RNQy0DvuxIoaak+T8zq/MxCltuMx6kU3cTWzqaHZM7bBxKgAyLfamrTcFyh4rUrkMzcBEENFkRng7//Px7vzwcUocygA4KGh6eGkef6/33yhgF4wUofUWgW2qyDNQm24OitLti7oQJBAPjOijg1gl6ytRrwdqPq+S4t7Y3ZHFjiis+7yhgZMZoS2JFeVtaQbbPfXzQ4eMExGEH2/lbOuMrsrEkxRUUNGfUCQQCT1apsFYDZwIcGSQ6DStEj4X+ukw5h/q2VnfI8B2u4EqbBbpzZ5DL7lo4yDDH85xifmLl0P3SrhSDeOSa/9ODZAkEA155OZHXi3GRs1MLNXjK07VM6CnK7wT/aYjpw4j97H/XzHs+t29Zga8BJhjzmUS5Vwlzlf584wAspJ2j+id/XvQJARDWLYj8xqkaYhh/jIFS+1k1O+h9DvZciRCwR/fx2iQGiCxGcMTSHCWnXxeO2lLeTtt9ige5dSF4uYhoAdQTpUQJBANoP3JGufyUusSp7UiRX/kUg1K2rfkrzg5MLNpPuKljs3mI/xGopddBogFNomZCbssGpUM+VFvNwnhZQByx58O4=";
var SERVER_PUBLICKEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsrxY7zwnU8/u9a5KClEjEHDiGyMXYBJUr+il5Pw9KsVqFuhydjV7EiMBTykQ4XuZdaBWqlA7KMOio9xsL8nuMZOSu3fsmuSvMjt6gX/7kd3TQO2Tbjs8sFokJ3LPYqrhWhHCxFe52USMiKEanKbSZch1uPF1+pQHfV4zo8Mu6FQIDAQAB";
var SERVER_PRIVATEKEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKyvFjvPCdTz+71rkoKUSMQcOIbIxdgElSv6KXk/D0qxWoW6HJ2NXsSIwFPKRDhe5l1oFaqUDsow6Kj3Gwvye4xk5K7d+ya5K8yO3qBf/uR3dNA7ZNuOzywWiQncs9iquFaEcLEV7nZRIyIoRqcptJlyHW48XX6lAd9XjOjwy7oVAgMBAAECgYEAk2mb506kq//j5R3RolsHizI0Jwt5qSCwXyxc/z4PxcmE5yerievG/Kto056VgjGxIgfahxWBUqVR1/uqQRas1A2j5/de8Y+LcpNrEuwF8YgOWmK3EAty0pgHQ1ezYSaxJ2AMBF427UrzMpGrB77UEzGE07GxbbC/sK/u66h0A/kCQQD89Q3OmWV8Gxie8XkWHeiUhseo3kZ9AYy7tRpsEkTkkWZAK2znphdHl35yDk0Cqu4uCe3usz6TfRlWu+3WK5k3AkEArsLXtUUt1IVeM0Z0Oxz8AWMb4v1lJiS4BhotZs7fyZ6DnMd+LIdfqQCLl9j3hCzdxEqIqmcuL2uGy1OYdfz9EwJAF+lGM9hWOoQJMMUcsBWFrbyL1Q+l1B04Y2n8JGkZsA16f+ha9A7ENpVAc6Gcb/seZqWzoxO4f5KcuZEsK0mVwwJAIp4qCJhZib2ZeWK9Z3BIYyX0wjQbs0CWy26oC7NzFQc3XvkNf1iZlGqtPDkYXrBchaOWCttBhNcx7ljy3HxuzQJAQxcxqCOUmLJah+Mtjb+aJQ2L6Lg3mBA62WNGxXDzpX2pAcJVZ7bNcsBq41rOpQEtQ8bEyj/Nfxxsxy/F57xuCQ==";
var jsrsasign = res.stream.toString();
// 执行jsrsasig,加载第三方库
eval(jsrsasign);
// RSAKey的扩展函数
RSAKey.prototype.getPEM = function(key, pemHeader) {
return hextopem(b64nltohex(key), pemHeader);
};
RSAKey.prototype.encryptB64 = function (text) {
return hextob64(this.encrypt(text));
};
RSAKey.prototype.decryptB64 = function (text) {
return this.decrypt(b64tohex(text));
};
RSAKey.prototype.getPrivateBaseKey = function () {
var keyPem = KEYUTIL.getPEM(this, "PKCS8PRV");
return pemtohex(keyPem);
};
RSAKey.prototype.getPrivateBaseKeyB64 = function () {
return hextob64(this.getPrivateBaseKey());
};
RSAKey.prototype.getPublicBaseKey = function () {
var keyPem = KEYUTIL.getPEM(this, "PKCS8PUB");
return pemtohex(keyPem);
};
RSAKey.prototype.getPublicBaseKeyB64 = function () {
return hextob64(this.getPublicBaseKey());
};
RSAKey.prototype.readPKCS8PrvKeyFromB64 = function (prvKeyB64) {
var prvKeyPem = this.getPEM(prvKeyB64, "PRIVATE KEY");
this.readPKCS8PrvKeyHex(pemtohex(prvKeyPem));
};
RSAKey.prototype.readPKCS8PubKeyFromB64 = function (pubKeyB64) {
var pubKeyPem = this.getPEM(pubKeyB64, "PUBLIC KEY");
this.readPKCS8PubKeyHex(pemtohex(pubKeyPem));
};
RSAKey.readPKCS9KeypairFromB64 = function(prvKeyB64, pubKeyB64) {
var prvKey = new RSAKey();
prvKey.readPKCS8PrvKeyFromB64(prvKeyB64);
var pubKey = new RSAKey();
pubKey.readPKCS8PubKeyFromB64(pubKeyB64);
var result = {};
result.prvKeyObj = prvKey;
result.pubKeyObj = pubKey;
return result;
};
/**
* 加密
* @param text 待加密的字符串
* @param key 加密的key
* @param isPub 是否使用publicKey加密,默认false
* @returns {*}
*/
function encrypt(text, key, isPub) {
// Encrypt with key...
var rsa = new RSAKey();
if(isPub) {
rsa.readPKCS8PubKeyFromB64(key);
} else {
rsa.readPKCS8PrvKeyFromB64(key);
}
var encrypted = rsa.encryptB64(text);
return encrypted;
}
/**
* 解密
* @param text 待解密的字符串
* @param key 解密的key
* @param isPub 是否使用publicKey解密,默认false
* @returns {*}
*/
function decrypt(text, key, isPub) {
// Decrypt with key...
var rsa = new RSAKey();
if(isPub) {
rsa.readPKCS8PubKeyFromB64(key);
} else {
rsa.readPKCS8PrvKeyFromB64(key);
}
var decrypted = rsa.decryptB64(text);
return decrypted;
}
var cPrv = new RSAKey();
cPrv.readPKCS8PrvKeyFromB64(CLIENT_PRIVATEKEY);
var message = pm.response.json().result.message;
console.log('密文:', message);
var decryptMessage = decrypt(message, cPrv.getPrivateBaseKeyB64());
console.log('解密后:', decryptMessage);
var expected = '服务端处理成功,客户端发送过来的内容为:Java中文';
pm.expect(decryptMessage).to.equal(expected);
});
});
http://localhost:8080/rsa/rest/api/v1/send
接口的参数以application/x-www-form-urlencoded
方式提供
message:
cPub:
message是加密后的消息, cPub是clinet端的公钥(server接收到client的请求后,将使用cPub加密返回的消息,clinet接收到response后,使用cPriv解密消息)
待完成
上述两个js的插件,并没有很好的支持postman中测试,还需要进一步学习和完善。