微信小程序接口加密怎么写?

  • 时间:
  • 来源: 网络

微信小程序请求的所有接口参数必须加密,那么小程序接口加密如何实现。

微信小程序接口实现加密教程:

场景

小程序请求的所有接口参数必须加密,后台返回数据也需要加密,并且增加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{

privateMapparams=newHashMap<>();

@SuppressWarnings("unchecked")

publicParameterRequestWrapper(HttpServletRequestrequest){

//将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似

super(request);

//将参数表,赋予给当前的Map以便于持有request中的参数

this.params.putAll(request.getParameterMap());

this.modifyParameterValues();

}

//重载一个构造方法

publicParameterRequestWrapper(HttpServletRequestrequest,MapextendParams){

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);

Mapmap=JSON.parseObject(decryptParameter);

Setset=map.keySet();

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

publicMapgetParameterMap(){

//returnsuper.getParameterMap();

returnparams;

}

@Override

publicEnumerationgetParameterNames(){

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(MapotherParams){//增加多个参数

for(Map.Entryentry:otherParams.entrySet()){

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中对过滤器进行配置

parameterFilter

com.xxx.xxx.config.filter.ParameterFilter

parameterFilter

*.json

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{

ListmapKes=newArrayList<>();

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转换器进行配置

text/html;charset=UTF-8

application/json

application/xml;charset=UTF-8

WriteMapNullValue

WriteNullNumberAsZero

WriteNullListAsEmpty

WriteNullStringAsEmpty

WriteNullBooleanAsFalse

WriteDateUseDateFormat

以上就是微信小程序接口加密如何实现的开发文档,更多小程序开发文档可以关注网站。

微商好助手小程序工具提供多类型商城/门店小程序制作,可视化编辑1秒生成5步上线。通过拖拽、拼接模块布局小程序商城页面,所看即所得,只需要美工就能做出精美商城。更多小程序请查看:小程序商店

价值1980元火爆的0基础小程序制作开发赚钱训练营免费看