网友真实露脸自拍10p,成人国产精品秘?久久久按摩,国产精品久久久久久无码不卡,成人免费区一区二区三区

小程序模板網

小程序接口加密

發布時間:2018-08-17 08:54 所屬欄目:小程序開發教程

場景

小程序請求的所有接口參數必須加密,后臺返回數據也需要加密,并且增加Token驗證

 

一、小程序端功能編寫

1.下載一份Js版的aesUtil.js源碼。【注:文章末尾會貼出所有的相關類文件】 
2.下載一份Js版的md5.js源碼。 
3.在pulic.js中進行加解密操作代碼如下,其中秘鑰和秘鑰偏移量要與后臺的一致。

 

  1. var CryptoJS = require('aesUtil.js'); //引用AES源碼js
    var md5 = require('md5.js')
    
    var key = CryptoJS.enc.Utf8.parse("76CAA1C88F7F8D1D"); //十六位十六進制數作為秘鑰
    var iv = CryptoJS.enc.Utf8.parse('91129048100F0494'); //十六位十六進制數作為秘鑰偏移量
    //解密方法
    function Decrypt(word) {
    var encryptedHexStr = CryptoJS.enc.Hex.parse(word);
    var srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
    var decrypt = CryptoJS.AES.decrypt(srcs, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
    });
    var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr.toString();
    }
    //加密方法
    function Encrypt(word) {
    var srcs = CryptoJS.enc.Utf8.parse(word);
    var encrypted = CryptoJS.AES.encrypt(srcs, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
    });
    return encrypted.ciphertext.toString().toUpperCase();
    }
    
    //暴露接口
    module.exports.Decrypt = Decrypt;
    module.exports.Encrypt = Encrypt;

4.在網絡請求幫助類中進行參數的加密和返回數據的解密操作。

 

  1. var aes = require('../utils/public.js')
    var md5 = require("../utils/md5.js")
    
    ...
    
    /**
    * 網絡請求
    */
    function request(method, loading, url, params, success, fail) {
    var url = BASE_URL + url;
    //請求參數轉為JSON字符串
    var jsonStr = JSON.stringify(params);
    console.log(url + ' params=> ' + jsonStr)
    //根據特定規則生成Token
    var token = productionToken(params);
    //加密請求參數
    var aesData = aes.Encrypt(jsonStr)
    console.log('請求=>明文參數:' + jsonStr)
    console.log('請求=>加密參數:' + aesData)
    ...
    wx.request({
    url: url,
    method: method,
    header: {
    'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
    'Token': token
    },
    data: {
    aesData: aesData
    },
    // data: params,
    success: function(res) {
    //判斷請求結果是否成功
    if (res.statusCode == 200 && res.data != '' && res.data != null) {
    //解密返回數據
    console.log('返回=>加密數據:' + res.data);
    var result = aes.Decrypt(res.data);
    console.log('返回=>明文數據:'+result);
    success(JSON.parse(result))
    } else {
    fail()
    }
    },
    fail: function(res) {
    fail()
    },
    })
    }

其中生成Token的規則,【生成Token的規則可根據具體的業務邏輯自己定義,我這里使用的規則是根據請求參數的字母排序取其value并加上當前時間戳再進行MD5加密】

 

  1. /**
    * 生成Token
    */
    function productionToken(params) {
    var obj = util.objKeySort(params);
    var value = '';
    for (var item in obj) {
    value += obj[item];
    }
    //加上當前時間戳
    value += util.getTokenDate(new Date())
    //去除所有空格
    value = value.replace(/\s+/g, "")
    //進行UTF-8編碼
    value = encodeURI(value);
    //進行MD5碼加密
    value = md5.hex_md5(value)
    return value;
    }
    //util的排序函數
    function objKeySort(obj) {
    //先用Object內置類的keys方法獲取要排序對象的屬性名,再利用Array原型上的sort方法對獲取的屬性名進行排序,newkey是一個數組
    var newkey = Object.keys(obj).sort();
    //創建一個新的對象,用于存放排好序的鍵值對  
    var newObj = {};
    //遍歷newkey數組
    for (var i = 0; i < newkey.length; i++) {
    //向新創建的對象中按照排好的順序依次增加鍵值對
    newObj[newkey[i]] = obj[newkey[i]];
    }
    //返回排好序的新對象
    return newObj;
    }
 

二、服務端功能編寫

由于初學SpringMVC,使用的方式不一定是最優最好的,如有不妥善之處,請各位看官多多指教  思路:

通過過濾器攔截請求參數,通過自定義參數包裝器對參數進行解密。  在攔截器獲取請求的Token并生成服務器端Token進行驗證。  對返回參數通過JSON轉換器進行加密處理。

思路圖  1.重寫HttpServletRequestWrapper,在自定義的HttpServletRequestWrapper 中對參數進行處理

 

  1. /**
    * Describe:請求參數包裝器 主要作用的過濾參數并解密
    * Created by 吳蜀黍 on 2018-08-07 09:37
    **/
    @Slf4j
    public class ParameterRequestWrapper extends HttpServletRequestWrapper {
    
    private Map<String, String[]> params = new HashMap<>();
    
    @SuppressWarnings("unchecked")
    public ParameterRequestWrapper(HttpServletRequest request) {
    // 將request交給父類,以便于調用對應方法的時候,將其輸出,其實父親類的實現方式和第一種new的方式類似
    super(request);
    //將參數表,賦予給當前的Map以便于持有request中的參數
    this.params.putAll(request.getParameterMap());
    this.modifyParameterValues();
    }
    
    //重載一個構造方法
    public ParameterRequestWrapper(HttpServletRequest request, Map<String, Object> extendParams) {
    this(request);
    addAllParameters(extendParams);//這里將擴展參數寫入參數表
    }
    
    private void modifyParameterValues() {//將parameter的值去除空格后重寫回去
    
    //獲取加密數據
    String aesParameter = getParameter(Constants.NetWork.AES_DATA);
    log.debug("[modifyParameterValues]==========>加密數據:{}", aesParameter);
    //解密
    String decryptParameter = null;
    try {
    decryptParameter = AesUtils.decrypt(aesParameter, Constants.AES.AES_KEY);
    log.debug("[modifyParameterValues]==========> 解密數據:{}", decryptParameter);
    Map<String, Object> map = JSON.parseObject(decryptParameter);
    Set<String> set = map.keySet();
    for (String key : set) {
    params.put(key, new String[]{String.valueOf(map.get(key))});
    }
    aesFlag(true);
    } catch (CommonBusinessException e) {
    aesFlag(false);
    log.error("[modifyParameterValues]", e);
    log.debug("[modifyParameterValues]==========>", e);
    }
    }
  2.  
  3. /**
  4. * 解密成功標志
  5. */
    private void aesFlag(boolean flag) {
    params.put(Constants.NetWork.AES_SUCCESS, new String[]{String.valueOf(flag)});
    }
    
    @Override
    public Map<String, String[]> getParameterMap() {
    // return super.getParameterMap();
    return params;
    }
    
    @Override
    public Enumeration<String> getParameterNames() {
    return new Vector<>(params.keySet()).elements();
    }
    
    @Override
    public String getParameter(String name) {//重寫getParameter,代表參數從當前類中的map獲取
    String[] values = params.get(name);
    if (values == null || values.length == 0) {
    return null;
    }
    return values[0];
    }
    
    public String[] getParameterValues(String name) {//同上
    return params.get(name);
    }
    
    
    public void addAllParameters(Map<String, Object> otherParams) {//增加多個參數
    for (Map.Entry<String, Object> entry : otherParams.entrySet()) {
    addParameter(entry.getKey(), entry.getValue());
    }
    }
    
    
    public void addParameter(String name, Object value) {//增加參數
    if (value != null) {
    if (value instanceof String[]) {
    params.put(name, (String[]) value);
    } else if (value instanceof String) {
    params.put(name, new String[]{(String) value});
    } else {
    params.put(name, new String[]{String.valueOf(value)});
    }
    }
    }
    }

新建過濾器,在攔截器中調用自定義的參數包裝器

 

  1. /**
    * Describe:請求參數過濾器
    * Created by 吳蜀黍 on 2018-08-07 10:02
    **/
    @Slf4j
    public class ParameterFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    //使用自定義的參數包裝器對參數進行處理
    ParameterRequestWrapper requestWrapper = new ParameterRequestWrapper((HttpServletRequest) servletRequest);
    filterChain.doFilter(requestWrapper, servletResponse);
    }
    
    @Override
    public void destroy() {
    }
    }

web.xml中對過濾器進行配置

 

  1. <!--過濾器-->
    <filter>
    <filter-name>parameterFilter</filter-name>
    <filter-class>com.xxx.xxx.config.filter.ParameterFilter</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>parameterFilter</filter-name>
    <!-- 過濾所有以.json結尾的資源-->
    <url-pattern>*.json</url-pattern>
    </filter-mapping>

AES加解密操作

 

  1. /**
    * Describe:AES 加密
    * Created by 吳蜀黍 on 2018-08-03 17:47
    **/
    public class AesUtils {
    private static final String CHARSET_NAME = "UTF-8";
    private static final String AES_NAME = "AES";
    private static final String ALGORITHM = "AES/CBC/PKCS7Padding";
    private static final String IV = Constants.AES.AES_IV;
    
    static {
    Security.addProvider(new BouncyCastleProvider());
    }
    
    /**
    * 加密
    */
    public static String encrypt(@NotNull String content, @NotNull String key) throws CommonBusinessException {
    try {
    Cipher cipher = Cipher.getInstance(ALGORITHM);
    SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(CHARSET_NAME), AES_NAME);
    AlgorithmParameterSpec paramSpec = new IvParameterSpec(IV.getBytes());
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, paramSpec);
    return ParseSystemUtil.parseByte2HexStr(cipher.doFinal(content.getBytes(CHARSET_NAME)));
    } catch (Exception ex) {
    throw new CommonBusinessException("加密失敗");
    }
    }
    
    /**
    * 解密
    */
    public static String decrypt(@NotNull String content, @NotNull String key) throws CommonBusinessException {
    try {
    Cipher cipher = Cipher.getInstance(ALGORITHM);
    SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(CHARSET_NAME), AES_NAME);
    AlgorithmParameterSpec paramSpec = new IvParameterSpec(IV.getBytes());
    cipher.init(Cipher.DECRYPT_MODE, keySpec, paramSpec);
    return new String(cipher.doFinal(Objects.requireNonNull(ParseSystemUtil.parseHexStr2Byte(content))), CHARSET_NAME);
    } catch (Exception ex) {
    throw new CommonBusinessException("解密失敗");
    }
    }
    
    }

2.新建攔截器,驗證Token以及解密的判斷

 

  1. @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
    //如果不是映射到方法直接通過
    if (!(handler instanceof HandlerMethod)) {
    return true;
    }
    //判斷參數包裝器中對請求參數的解密是否成功
    boolean aesSuccess = Boolean.parseBoolean(httpServletRequest.getParameter(Constants.NetWork.AES_SUCCESS));
    if (!aesSuccess) {
    this.sendMsg(Constants.NetWork.CODE_DECRYPTION_FAILURE, Constants.NetWork.MEG_AES_FAIL, httpServletResponse);
    return false;
    }
    //獲取客戶端上傳Token
    String token = httpServletRequest.getHeader(Constants.NetWork.TOKEN_HEAD_KEY);
    if (StringUtils.isNullOrEmpty(token)) {
    sendMsg(Constants.NetWork.CODE_TOKEN_INVALID, Constants.NetWork.MSG_TOKEN_EMPTY, httpServletResponse);
    return false;
    }
    //驗證Token的有效性
    if (!TokenUtils.verificationToken(token, httpServletRequest.getParameterMap())) {
    sendMsg(Constants.NetWork.CODE_TOKEN_INVALID, Constants.NetWork.MSG_TOKEN_INVALID, httpServletResponse);
    return false;
    }
    return true;
    }
    
    /**
    * 驗證失敗 發送消息
    */
    private void sendMsg(String msgCode, String msg, HttpServletResponse httpServletResponse) throws IOException {
    httpServletResponse.setContentType("application/json; charset=utf-8");
    PrintWriter writer = httpServletResponse.getWriter();
    String jsonString = JSON.toJSONString(StandardResult.create(msgCode, msg));
    try {
    //對驗證失敗的返回信息進行加密
    jsonString = AesUtils.encrypt(jsonString, Constants.AES.AES_KEY);
    } catch (CommonBusinessException e) {
    e.printStackTrace();
    jsonString = null;
    log.error("[sendMsg]", e);
    }
    writer.print(jsonString);
    writer.close();
    httpServletResponse.flushBuffer();
    }

在spring中對攔截器注冊

 

  1. <mvc:interceptors>
    <!-- 使用bean定義一個Interceptor,直接定義在mvc:interceptors根下面的Interceptor將攔截所有的請求 -->
    <mvc:interceptor>
    <!-- 攔截所有請求 -->
    <mvc:mapping path="/**"/>
    <!-- 需排除攔截的地址 -->
    <!--<mvc:exclude-mapping path="/"/>-->
    <bean class="com.xxx.xxx.config.interceptor.AsyncHandlerInterceptor"/>
    </mvc:interceptor>
    </mvc:interceptors>

Token的驗證

 

  1. /**
    * Describe:Token幫助類
    * Created by 吳蜀黍 on 2018-08-04 14:48
    **/
    @Slf4j
    public class TokenUtils {
    /**
    * 驗證Token
    *
    * @param token 客戶端上傳Token
    * @param mapTypes 請求參數集合
    * @return boolean
    */
    public static boolean verificationToken(String token, Map mapTypes) {
    try {
    return StringUtils.saleEquals(token, getToken(mapTypes));
    } catch (UnsupportedEncodingException e) {
    log.error("[verificationToken]", e);
    return false;
    }
    }
    
    
    /**
    * 通過客戶端請求參數產生Token
    */
    private static String getToken(Map mapTypes) throws UnsupportedEncodingException {
    List<String> mapKes = new ArrayList<>();
    for (Object obj : mapTypes.keySet()) {
    String value = 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);
    StringBuilder sb = new StringBuilder();
    for (String key : mapKes) {
    String value = ((String[]) mapTypes.get(key))[0];
    sb.append(value);
    }
    //加上時間戳,去除所有空格 進行MD5加密
    String string = sb.append(DateUtils.getDateStr(DateUtils.FORMAT_YYYYMMDDHH)).toString().replace(" ", "");
    return MD5.getMD5(URLEncoder.encode(string, "UTF-8"));
    }
    }

3.對返回數據進行加密處理,新建JSON轉換器繼承自阿里的FastJsonHttpMessageConverter

 

  1. /**
    * Describe:Json轉換器 將返回數據加密
    * Created by 吳蜀黍 on 2018-08-07 13:57
    **/
    @Slf4j
    public class JsonMessageConverter extends FastJsonHttpMessageConverter {
    
    @Override
    protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException,
    HttpMessageNotWritableException {
    OutputStream out = outputMessage.getBody();
    try {
    String jsonString = 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 (CommonBusinessException e) {
    e.printStackTrace();
    log.error("[writeInternal]======>", e);
    }
    out.close();
    }
    }

spring中對JSON轉換器進行配置



<mvc:message-converters>
<!--<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">-->
<bean class="com.xxx.xxx.config.converter.JsonMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json</value>
<value>application/xml;charset=UTF-8</value>
</list>
</property>
<property name="features">
<list>
<!-- 默認的意思就是不配置這個屬性,配置了就不是默認了 -->
<!-- 是否輸出值為null的字段 ,默認是false-->
<value>WriteMapNullValue</value>
<value>WriteNullNumberAsZero</value>
<value>WriteNullListAsEmpty</value>
<value>WriteNullStringAsEmpty</value>
<value>WriteNullBooleanAsFalse</value>
<value>WriteDateUseDateFormat</value>
</list>
</property>
</bean>
</mvc:message-converters>

三、測試

1.控制器

 

/**
* Describe:加解密測試
* Created by 吳蜀黍 on 2018-08-08 11:13
**/
@Slf4j
@Controller
@RequestMapping(value = "/test")
public class TestController {

@RequestMapping(value = "/test.json")
@ResponseBody
private StandardResult test(Test test) {
log.debug("[TestController]======> 接口參數:{}", test.toString());
return StandardResult.createSuccessObj("測試成功");
}
}

2.測試結果

客戶端

服務端  在后臺自動加解密模塊中,原本是打算都在JSON轉換器中處理,通過readInternal()解密,再通過writeInternal()加密,奈何調試的過程中總會出現一些未知錯誤,如有相關大神,請幫忙指點迷津!通過過濾器來處理參數有些大材小用的意思,如果哪位有更好的方案和處理方式歡迎留言,感激不盡!!! 

 


易優小程序(企業版)+靈活api+前后代碼開源 碼云倉庫:starfork
本文地址:http://www.xiuhaier.com/wxmini/doc/course/24725.html 復制鏈接 如需定制請聯系易優客服咨詢:800182392 點擊咨詢
QQ在線咨詢
AI智能客服 ×