微信小程序接口加密怎么写?
- 时间:
- 来源: 网络
微信小程序请求的所有接口参数必须加密,那么小程序接口加密如何实现。
微信小程序接口实现加密教程:
场景
小程序请求的所有接口参数必须加密,后台返回数据也需要加密,并且增加Token验证
一、小程序端功能编写
1.下载一份Js版的aesUtil.js源码。【注:文章末尾会贴出所有的相关类文件】
2.下载一份Js版的md5.js源码。
3.在pulic.js中进行加解密操作代码如下,其中秘钥和秘钥偏移量要与后台的一致。
varCryptoJS=require('aesUtil.js');//引用AES源码js
varmd5=require('md5.js')
varkey=CryptoJS.enc.Utf8.parse("76CAA1C88F7F8D1D");//十六位十六进制数作为秘钥
variv=CryptoJS.enc.Utf8.parse('91129048100F0494');//十六位十六进制数作为秘钥偏移量
//解密方法
functionDecrypt(word){
varencryptedHexStr=CryptoJS.enc.Hex.parse(word);
varsrcs=CryptoJS.enc.Base64.stringify(encryptedHexStr);
vardecrypt=CryptoJS.AES.decrypt(srcs,key,{
iv:iv,
mode:CryptoJS.mode.CBC,
padding:CryptoJS.pad.Pkcs7
});
vardecryptedStr=decrypt.toString(CryptoJS.enc.Utf8);
returndecryptedStr.toString();
}
//加密方法
functionEncrypt(word){
varsrcs=CryptoJS.enc.Utf8.parse(word);
varencrypted=CryptoJS.AES.encrypt(srcs,key,{
iv:iv,
mode:CryptoJS.mode.CBC,
padding:CryptoJS.pad.Pkcs7
});
returnencrypted.ciphertext.toString().toUpperCase();
}
//暴露接口
module.exports.Decrypt=Decrypt;
module.exports.Encrypt=Encrypt;
4.在网络请求帮助类中进行参数的加密和返回数据的解密操作。
varaes=require('')
varmd5=require("")
...
functionrequest(method,loading,url,params,success,fail){
varurl=BASE_URL+url;
//请求参数转为JSON字符串
varjsonStr=JSON.stringify(params);
console.log(url+'params=>'+jsonStr)
//根据特定规则生成Token
vartoken=productionToken(params);
//加密请求参数
varaesData=aes.Encrypt(jsonStr)
console.log('请求=>明文参数:'+jsonStr)
console.log('请求=>加密参数:'+aesData)
...
wx.request({
url:url,
method:method,
header:{
'Content-Type':'application/x-',
'Token':token
},
data:{
aesData:aesData
},
//data:params,
success:function(res){
//判断请求结果是否成功
if(res.statusCode==200&&res.data!=''&&res.data!=null){
//解密返回数据
console.log('返回=>加密数据:'+res.data);
varresult=aes.Decrypt(res.data);
console.log('返回=>明文数据:'+result);
success(JSON.parse(result))
}else{
fail()
}
},
fail:function(res){
fail()
},
})
}
其中生成Token的规则,【生成Token的规则可根据具体的业务逻辑自己定义,我这里使用的规则是根据请求参数的字母排序取其value并加上当前时间戳再进行MD5加密】
functionproductionToken(params){
varobj=util.objKeySort(params);
varvalue='';
for(variteminobj){
value+=obj[item];
}
//加上当前时间戳
value+=util.getTokenDate(newDate())
//去除所有空格
value=value.replace(/\s+/g,"")
//进行UTF-8编码
value=encodeURI(value);
//进行MD5码加密
value=md5.hex_md5(value)
returnvalue;
}
//util的排序函数
functionobjKeySort(obj){
//先用Object内置类的keys方法获取要排序对象的属性名,再利用Array原型上的sort方法对获取的属性名进行排序,newkey是一个数组
varnewkey=Object.keys(obj).sort();
//创建一个新的对象,用于存放排好序的键值对
varnewObj={};
//遍历newkey数组
for(vari=0;i //向新创建的对象中按照排好的顺序依次增加键值对 newObj[newkey[i]]=obj[newkey[i]]; } //返回排好序的新对象 returnnewObj; } 二、服务端功能编写 由于初学SpringMVC,使用的方式不一定是最优最好的,如有不妥善之处,请各位看官多多指教思路: 通过过滤器拦截请求参数,通过自定义参数包装器对参数进行解密。在拦截器获取请求的Token并生成服务器端Token进行验证。对返回参数通过JSON转换器进行加密处理。 1.重写HttpServletRequestWrapper,在自定义的HttpServletRequestWrapper中对参数进行处理 @Slf4j publicclassParameterRequestWrapperextendsHttpServletRequestWrapper{ privateMap @SuppressWarnings("unchecked") publicParameterRequestWrapper(HttpServletRequestrequest){ //将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似 super(request); //将参数表,赋予给当前的Map以便于持有request中的参数 this.params.putAll(request.getParameterMap()); this.modifyParameterValues(); } //重载一个构造方法 publicParameterRequestWrapper(HttpServletRequestrequest,Map this(request); addAllParameters(extendParams);//这里将扩展参数写入参数表 } privatevoidmodifyParameterValues(){//将parameter的值去除空格后重写回去 //获取加密数据 StringaesParameter=getParameter(Constants.NetWork.AES_DATA); log.debug("[modifyParameterValues]==========>加密数据:{}",aesParameter); //解密 StringdecryptParameter=null; try{ decryptParameter=AesUtils.decrypt(aesParameter,Constants.AES.AES_KEY); log.debug("[modifyParameterValues]==========>解密数据:{}",decryptParameter); Map Set for(Stringkey:set){ params.put(key,newString[]{String.valueOf(map.get(key))}); } aesFlag(true); }catch(CommonBusinessExceptione){ aesFlag(false); log.error("[modifyParameterValues]",e); log.debug("[modifyParameterValues]==========>",e); } } privatevoidaesFlag(booleanflag){ params.put(Constants.NetWork.AES_SUCCESS,newString[]{String.valueOf(flag)}); } @Override publicMap //returnsuper.getParameterMap(); returnparams; } @Override publicEnumeration returnnewVector<>(params.keySet()).elements(); } @Override publicStringgetParameter(Stringname){//重写getParameter,代表参数从当前类中的map获取 String[]values=params.get(name); if(values==null||values.length==0){ returnnull; } returnvalues[0]; } publicString[]getParameterValues(Stringname){//同上 returnparams.get(name); } publicvoidaddAllParameters(Map for(Map.Entry addParameter(entry.getKey(),entry.getValue()); } } publicvoidaddParameter(Stringname,Objectvalue){//增加参数 if(value!=null){ if(valueinstanceofString[]){ params.put(name,(String[])value); }elseif(valueinstanceofString){ params.put(name,newString[]{(String)value}); }else{ params.put(name,newString[]{String.valueOf(value)}); } } } } 新建过滤器,在拦截器中调用自定义的参数包装器 @Slf4j publicclassParameterFilterimplementsFilter{ @Override publicvoidinit(FilterConfigfilterConfig)throwsServletException{ } @Override publicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainfilterChain)throwsIOException,ServletException{ //使用自定义的参数包装器对参数进行处理 ParameterRequestWrapperrequestWrapper=newParameterRequestWrapper((HttpServletRequest)servletRequest); filterChain.doFilter(requestWrapper,servletResponse); } @Override publicvoiddestroy(){ } } web.xml中对过滤器进行配置 AES加解密操作 publicclassAesUtils{ privatestaticfinalStringCHARSET_NAME="UTF-8"; privatestaticfinalStringAES_NAME="AES"; privatestaticfinalStringALGORITHM="AES/CBC/PKCS7Padding"; privatestaticfinalStringIV=Constants.AES.AES_IV; static{ Security.addProvider(newBouncyCastleProvider()); } publicstaticStringencrypt(@NotNullStringcontent,@NotNullStringkey)throwsCommonBusinessException{ try{ Ciphercipher=Cipher.getInstance(ALGORITHM); SecretKeySpeckeySpec=newSecretKeySpec(key.getBytes(CHARSET_NAME),AES_NAME); AlgorithmParameterSpecparamSpec=newIvParameterSpec(IV.getBytes()); cipher.init(Cipher.ENCRYPT_MODE,keySpec,paramSpec); returnParseSystemUtil.parseByte2HexStr(cipher.doFinal(content.getBytes(CHARSET_NAME))); }catch(Exceptionex){ thrownewCommonBusinessException("加密失败"); } } publicstaticStringdecrypt(@NotNullStringcontent,@NotNullStringkey)throwsCommonBusinessException{ try{ Ciphercipher=Cipher.getInstance(ALGORITHM); SecretKeySpeckeySpec=newSecretKeySpec(key.getBytes(CHARSET_NAME),AES_NAME); AlgorithmParameterSpecparamSpec=newIvParameterSpec(IV.getBytes()); cipher.init(Cipher.DECRYPT_MODE,keySpec,paramSpec); returnnewString(cipher.doFinal(Objects.requireNonNull(ParseSystemUtil.parseHexStr2Byte(content))),CHARSET_NAME); }catch(Exceptionex){ thrownewCommonBusinessException("解密失败"); } } } 2.新建拦截器,验证Token以及解密的判断 @Override publicbooleanpreHandle(HttpServletRequesthttpServletRequest,HttpServletResponsehttpServletResponse,Objecthandler)throwsException{ //如果不是映射到方法直接通过 if(!(handlerinstanceofHandlerMethod)){ returntrue; } //判断参数包装器中对请求参数的解密是否成功 booleanaesSuccess=Boolean.parseBoolean(httpServletRequest.getParameter(Constants.NetWork.AES_SUCCESS)); if(!aesSuccess){ this.sendMsg(Constants.NetWork.CODE_DECRYPTION_FAILURE,Constants.NetWork.MEG_AES_FAIL,httpServletResponse); returnfalse; } //获取客户端上传Token Stringtoken=httpServletRequest.getHeader(Constants.NetWork.TOKEN_HEAD_KEY); if(StringUtils.isNullOrEmpty(token)){ sendMsg(Constants.NetWork.CODE_TOKEN_INVALID,Constants.NetWork.MSG_TOKEN_EMPTY,httpServletResponse); returnfalse; } //验证Token的有效性 if(!TokenUtils.verificationToken(token,httpServletRequest.getParameterMap())){ sendMsg(Constants.NetWork.CODE_TOKEN_INVALID,Constants.NetWork.MSG_TOKEN_INVALID,httpServletResponse); returnfalse; } returntrue; } privatevoidsendMsg(StringmsgCode,Stringmsg,HttpServletResponsehttpServletResponse)throwsIOException{ httpServletResponse.setContentType("application/json;charset=utf-8"); PrintWriterwriter=httpServletResponse.getWriter(); StringjsonString=JSON.toJSONString(StandardResult.create(msgCode,msg)); try{ //对验证失败的返回信息进行加密 jsonString=AesUtils.encrypt(jsonString,Constants.AES.AES_KEY); }catch(CommonBusinessExceptione){ e.printStackTrace(); jsonString=null; log.error("[sendMsg]",e); } writer.print(jsonString); writer.close(); httpServletResponse.flushBuffer(); } 在spring中对拦截器注册 @Slf4j publicclassTokenUtils{ publicstaticbooleanverificationToken(Stringtoken,MapmapTypes){ try{ returnStringUtils.saleEquals(token,getToken(mapTypes)); }catch(UnsupportedEncodingExceptione){ log.error("[verificationToken]",e); returnfalse; } } privatestaticStringgetToken(MapmapTypes)throwsUnsupportedEncodingException{ List for(Objectobj:mapTypes.keySet()){ Stringvalue=String.valueOf(obj); //去除参数中的加密相关key if(StringUtils.saleEquals(value,Constants.NetWork.AES_SUCCESS)|| StringUtils.saleEquals(value,Constants.NetWork.AES_DATA)){ break; } mapKes.add(value); } //排序key Collections.sort(mapKes); StringBuildersb=newStringBuilder(); for(Stringkey:mapKes){ Stringvalue=((String[])mapTypes.get(key))[0]; sb.append(value); } //加上时间戳,去除所有空格进行MD5加密 Stringstring=sb.append(DateUtils.getDateStr(DateUtils.FORMAT_YYYYMMDDHH)).toString().replace("",""); returnMD5.getMD5(URLEncoder.encode(string,"UTF-8")); } } 3.对返回数据进行加密处理,新建JSON转换器继承自阿里的FastJsonHttpMessageConverter @Slf4j publicclassJsonMessageConverterextendsFastJsonHttpMessageConverter{ @Override protectedvoidwriteInternal(Objectobject,HttpOutputMessageoutputMessage)throwsIOException, HttpMessageNotWritableException{ OutputStreamout=outputMessage.getBody(); try{ StringjsonString=JSON.toJSONString(object); log.debug("[writeInternal]======>返回明文数据:{}"+jsonString); //对返回数据进行AES加密 jsonString=AesUtils.encrypt(jsonString,Constants.AES.AES_KEY); log.debug("[writeInternal]======>返回加密数据:{}"+jsonString); out.write(jsonString.getBytes()); }catch(CommonBusinessExceptione){ e.printStackTrace(); log.error("[writeInternal]======>",e); } out.close(); } } spring中对JSON转换器进行配置 以上就是微信小程序接口加密如何实现的开发文档,更多小程序开发文档可以关注网站。 微商好助手小程序工具提供多类型商城/门店小程序制作,可视化编辑1秒生成5步上线。通过拖拽、拼接模块布局小程序商城页面,所看即所得,只需要美工就能做出精美商城。更多小程序请查看:小程序商店 价值1980元火爆的0基础小程序制作开发赚钱训练营免费看