概述
使用对称加密的方式实现。 前端基于crypto-js。 uni-app框架中是在uni.request的基础上,在拦截器中处理的。 springboot在Filter中完成解密工作。
uni-app
项目中引入crypto-js。
npm install crypto-js
加密方法
const SECRET_KEY = CryptoJS. enc. Utf8. parse ( "1234123412341234" ) ; function encrypt ( msg ) { const dataHex = CryptoJS. enc. Utf8. parse ( msg) ; const encrypted = CryptoJS. AES . encrypt ( dataHex, SECRET_KEY , { mode : CryptoJS. mode. ECB , padding : CryptoJS. pad. Pkcs7} ) ; return encrypted. ciphertext. toString ( CryptoJS. enc. Base64) ;
}
解密方法
function decrypt ( msg ) { const encryptedHexStr = CryptoJS. enc. Hex. parse ( msg) ; const str = CryptoJS. enc. Base64. stringify ( encryptedHexStr) ; const decrypt = CryptoJS. AES . decrypt ( str, SECRET_KEY , { mode : CryptoJS. mode. ECB , padding : CryptoJS. pad. Pkcs7} ) ; return decrypt. toString ( CryptoJS. enc. Utf8) ;
}
request拦截器
uni. addInterceptor ( 'request' , { invoke ( args ) { let plaintext = JSON . stringify ( args. data) ; plaintext = encodeURIComponent ( plaintext) ; const textArray = [ ] ; while ( plaintext. length > 15 ) { textArray. push ( plaintext. substring ( 0 , 16 ) ) ; plaintext = plaintext. substring ( 16 ) ; } textArray. push ( plaintext) ; const encryptParamArray = [ ] ; textArray. forEach ( item => { encryptParamArray. push ( btoa ( encrypt ( item) ) ) ; } ) args. data = { "encryptParams" : encryptParamArray} ; } , success ( args ) { } , fail ( err ) { } , complete ( res ) { }
} ) ;
备注
使用encodeURIComponent方法是为了处理 字符“+”,这个对应java解密的时候存在问题。 该模式默认解密长度出限制在16个字符中,所以需要将待加密的信息分解成单个字符长度小于16的字符组成数组。
Springboot
DecryptFilter,解密拦截器
import cn. hutool. json. JSONUtil ;
import org. apache. commons. codec. binary. Base64 ;
import org. springframework. http. HttpMethod ; import javax. crypto. Cipher ;
import javax. crypto. spec. SecretKeySpec ;
import javax. servlet. * ;
import javax. servlet. annotation. WebFilter ;
import javax. servlet. http. HttpServletRequest ;
import java. io. BufferedReader ;
import java. io. IOException ;
import java. io. InputStream ;
import java. io. InputStreamReader ;
import java. net. URLDecoder ;
import java. nio. charset. StandardCharsets ; @WebFilter ( urlPatterns = "/*" )
public class DecryptFilter implements Filter { private String word; public DecryptFilter ( String word) { this . word = word; } @Override public void init ( FilterConfig filterConfig) throws ServletException { } @Override public void doFilter ( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException , ServletException { HttpServletRequest httpRequest = ( HttpServletRequest ) servletRequest; if ( HttpMethod . OPTIONS . matches ( httpRequest. getMethod ( ) ) ) { filterChain. doFilter ( httpRequest, servletResponse) ; return ; } String encryptedData = "" ; if ( httpRequest. getHeader ( "Content-Type" ) . contains ( "x-www-form-urlencoded" ) ) { encryptedData = httpRequest. getParameter ( "encryptParams" ) ; } else if ( httpRequest. getHeader ( "Content-Type" ) . contains ( "json" ) ) { StringBuilder stringBuilder = new StringBuilder ( ) ; try ( InputStream inputStream = httpRequest. getInputStream ( ) ; BufferedReader bufferedReader = new BufferedReader ( new InputStreamReader ( inputStream, StandardCharsets . UTF_8 ) ) ) { String line; while ( ( line = bufferedReader. readLine ( ) ) != null ) { stringBuilder. append ( line) ; } } encryptedData = JSONUtil . parseObj ( stringBuilder. toString ( ) ) . get ( "encryptParams" ) . toString ( ) ; encryptedData = encryptedData. replaceAll ( "[\\[\\]\"]" , "" ) ; } String [ ] ciphertextArray = encryptedData. split ( "," ) ; String decryptedData = "" ; try { decryptedData = decrypt ( ciphertextArray) ; } catch ( Exception e) { throw new RuntimeException ( "解密失败!" , e) ; } ServletRequest modifiedRequest = new BodyRewritingRequestWrapper ( httpRequest, decryptedData) ; filterChain. doFilter ( modifiedRequest, servletResponse) ; } @Override public void destroy ( ) { } private String decrypt ( String [ ] encryptedTextArray) throws Exception { StringBuilder paramsJson = new StringBuilder ( "" ) ; Cipher cipher = Cipher . getInstance ( "AES/ECB/PKCS5Padding" ) ; byte [ ] keyBytes = word. getBytes ( StandardCharsets . UTF_8 ) ; SecretKeySpec keySpec = new SecretKeySpec ( keyBytes, "AES" ) ; cipher. init ( Cipher . DECRYPT_MODE , keySpec) ; for ( String ciphertext : encryptedTextArray) { byte [ ] decode = java. util. Base64. getDecoder ( ) . decode ( ciphertext) ; byte [ ] encryptedBytes = Base64 . decodeBase64 ( decode) ; byte [ ] decryptedBytes = cipher. doFinal ( encryptedBytes) ; paramsJson. append ( new String ( decryptedBytes, StandardCharsets . UTF_8 ) ) ; } return URLDecoder . decode ( paramsJson. toString ( ) , "UTF-8" ) ; }
}
BodyRewritingRequestWrapper,重写的ServletRequest对相关
import cn. hutool. json. JSONObject ;
import cn. hutool. json. JSONUtil ; import javax. servlet. ReadListener ;
import javax. servlet. ServletInputStream ;
import javax. servlet. http. HttpServletRequest ;
import javax. servlet. http. HttpServletRequestWrapper ;
import java. io. BufferedReader ;
import java. io. ByteArrayInputStream ;
import java. io. IOException ;
import java. io. InputStreamReader ;
import java. util. HashMap ;
import java. util. Map ; public class BodyRewritingRequestWrapper extends HttpServletRequestWrapper { private String body; private JSONObject map; public BodyRewritingRequestWrapper ( HttpServletRequest request, String body) { super ( request) ; this . body = body; this . map = JSONUtil . parseObj ( body) ; } @Override public String getParameter ( String name) { if ( map. containsKey ( name) ) { return map. get ( name) . toString ( ) ; } return super . getParameter ( name) ; } @Override public Map < String , String [ ] > getParameterMap ( ) { Map < String , String [ ] > originalParameters = super . getParameterMap ( ) ; Map < String , String [ ] > rewriteMap = new HashMap < > ( originalParameters) ; map. forEach ( ( key, value) -> rewriteMap. put ( key, new String [ ] { value. toString ( ) } ) ) ; return rewriteMap; } @Override public ServletInputStream getInputStream ( ) throws IOException { final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream ( body. getBytes ( ) ) ; return new ServletInputStream ( ) { public int read ( ) throws IOException { return byteArrayInputStream. read ( ) ; } @Override public boolean isFinished ( ) { return false ; } @Override public boolean isReady ( ) { return true ; } @Override public void setReadListener ( ReadListener readListener) { } } ; } @Override public BufferedReader getReader ( ) throws IOException { return new BufferedReader ( new InputStreamReader ( this . getInputStream ( ) ) ) ; }
}
注册拦截器
import org. springframework. beans. factory. annotation. Value ;
import org. springframework. boot. web. servlet. FilterRegistrationBean ;
import org. springframework. context. annotation. Bean ;
import org. springframework. context. annotation. Configuration ;
import org. springframework. http. HttpMethod ;
import org. springframework. web. cors. CorsConfiguration ;
import org. springframework. web. cors. UrlBasedCorsConfigurationSource ;
import org. springframework. web. filter. CorsFilter ; @Configuration
public class WebConfig { @Value ( "${decrypt.word}" ) private String word; @Bean public FilterRegistrationBean < DecryptFilter > myFilterRegistration ( ) { FilterRegistrationBean < DecryptFilter > registration = new FilterRegistrationBean < > ( ) ; registration. setFilter ( new DecryptFilter ( word) ) ; registration. addUrlPatterns ( "/*" ) ; registration. setName ( "decryptFilter" ) ; registration. setOrder ( 1 ) ; return registration; }
}