基於sm-crypto的sm4的請求加密&響應加密

有時候需要對項目的請求和返回值進行加密請求,因而筆者使用了sm4,讀者也可以使用別的庫如md5

封裝加解密:

// ciphertext.js
const sm4 = require('sm-crypto').sm4
// 此爲密文key,非常重要
export const CIPHERTEXT = `wzdxcskwzdxcskwzdxcskwzdxcskwzdxcsk` //我真的想喫燒烤我真的想喫燒烤我真的想喫燒烤我真的想喫燒烤
/**
 * 參考:
 * https://github.com/JuneAndGreen/sm-crypto#sm4
 * 
 * */
// 數據加密 用於axios請求攔截器
export const encryptSm4 = ( requestParams = ''  )=>{
  if (!requestParams) return 
   return sm4.encrypt(requestParams, CIPHERTEXT)
}

// 數據解密 用於axios相應攔截器
export const decryptSm4 = ( result = ''  )=>{
  if (!result) return 
   return sm4.decrypt(result, CIPHERTEXT)
}

響應/請求攔截中使用加解密方法,以下只寫要改動的,其餘的可以不變

// request.js
import axios from "axios";
import store from "../store";
import { encryptSm4, decryptSm4 } from "./ciphertext";
//生成axios實例
const service = axios.create({
  // axios默認統一數據
  timeout: 120000, //指定請求超時的毫秒數(0 表示無超時時間)
  // baseURL:xxxx, //可能有不同類型的api地址,可以在這裏設置baseurl,後續中用以對比是否源於指定的url
  // 如果要校驗請求類型,就需要先在這裏聲明`contenttype`
  headers: {
    "Content-Type": "application/json" // 設置默認json格式以規避在攔截器中拿不到 content-type問題
  }
});
// 確認config配置項
const configCheck = (conf, type) => {
  // 此處可根據需要自定義校驗
  const isPost = conf.method.toUpperCase() === `POST`; // 是否post
  // const jsonReg =  /application\/json/; // 正則表達式匹配'application/json'
  // const isJSON = jsonReg.test(conf.headers[`Content-Type`])    // 是否JSON
  const isFromBaseURL = conf.baseURL.includes(process.env.VUE_APP_BASE_API); //是否基於baseurl
  // console.log('isFromBaseURL :>> ', conf.baseURL, isFromBaseURL);
  // console.log('process.env.VUE_APP_BASE_API :>> ', process.env.VUE_APP_BASE_API); 
  return {
    send: [isFromBaseURL, isPost],
    receive: [isFromBaseURL]
  }[type].every(v => v);
};
// 請求攔截配置
/**
 * 有以下方可進行加密:
 *   configCheck 爲true
 *   明確`store`中`encryption`爲1  後端控制是否需要將請求/響應加密
 service.interceptors.request.use(config=>{
  ...other code...
  const isEncrypted = store.encryption === 1
  if (isEncrypted && configCheck(config, `send`)) {
      try {
        const reqData = encryptSm4(JSON.stringify(config[`data`]));
        config[`data`] = reqData ? reqData : config[`data`];
      } catch (error) {
        console.log("error :>> ", error);
      }
  }
  ...other code...
return config
})

// 響應攔截

service.interceptors.response.use(response=>{
    let res = response.data; // 這裏故意用了`let` 因爲加密態下可能要改
// ---------------------- 此處爲解密校驗
    const isEncrypted = store.encryption === 1
    // 加密態下返回的只有一堆加密str,因而沒有`res.cdoe`屬性
    if (!res.code && configCheck(response.config, `receive`) && isEncrypted) {
      try {
        // 解析加密數據
        res = JSON.parse(decryptSm4(res));
        if (typeof res === `string`) {
          console.log(`--------------------`);
          console.log("res :解析失敗返回值>> ", res);
          console.log("失敗接口路徑爲 :>> ", response.config.url);
          console.log("接口方法爲 :>> ", response.config.method);
          console.log(`--------------------`);
        }
        // 解密後數據不一定是正常返回值,因而這裏做了簡單校驗
        if (res.code && Number(res.code) !== 200) {
          Message({
            message: res.msg || "當前網絡繁忙,請稍後重試!",
            type: "error",
            duration: 3 * 1000
          });
          return Promise.reject(
            new Error(res.msg || "當前網絡繁忙,請稍後重試")
          );
        }
      } catch (error) {
        console.log(`--------------------`);
        console.log("error :>解析異常告警> ", error);
        console.log("res :解析失敗返回值>> ", res);
        console.log("失敗接口路徑爲 :>> ", response.config.url);
        console.log("接口方法爲 :>> ", response.config.method);
        console.log(`--------------------`);
      }
    }
// 👆----------------------------------- 此處爲解密校驗
  // 接下來可以寫正常明文校驗,不表
    return res
})

以上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章