第一步:产生密钥
+ *方式一:系统生成密钥
+ * 自动生成密钥 + * @explain + * @return + */ + public static byte[] generateKey() throws Exception { + return generateKey(DEFAULT_KEY_SIZE); + } + + /** + * @explain + * @param keySize + * @return + * @throws Exception + */ + public static byte[] generateKey(int keySize) throws Exception { + KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME); + kg.init(keySize, new SecureRandom()); + return kg.generateKey().getEncoded(); + } + + /** + *方法二:自己提供16进制的密钥
+ *第二步:加密
+ * sm4加密 + * @explain 加密模式:ECB + * 密文长度不固定,会随着被加密字符串长度的变化而变化 + * @param hexKey + * 16进制密钥(忽略大小写) + * @param paramStr + * 待加密字符串 + * @return 返回16进制的加密字符串 + * @throws Exception + */ + public static String encryptEcb(String hexKey, String paramStr) throws Exception { + String cipherText = ""; + // 16进制字符串-->byte[] + byte[] keyData = ByteUtils.fromHexString(hexKey); + // String-->byte[] + byte[] srcData = paramStr.getBytes(ENCODING); + // 加密后的数组 + byte[] cipherArray = encrypt_Ecb_Padding(keyData, srcData); + // byte[]-->hexString + cipherText = ByteUtils.toHexString(cipherArray); + return cipherText; + } + + /** + * 加密模式之Ecb + * @explain + * @param key + * @param data + * @return + * @throws Exception + */ + public static byte[] encrypt_Ecb_Padding(byte[] key, byte[] data) throws Exception { + Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key); + return cipher.doFinal(data); + } + + /** + * sm4解密 + * @explain 解密模式:采用ECB + * @param hexKey + * 16进制密钥 + * @param cipherText + * 16进制的加密字符串(忽略大小写) + * @return 解密后的字符串 + * @throws Exception + */ + public static String decryptEcb(String hexKey, String cipherText) throws Exception { + // 用于接收解密后的字符串 + String decryptStr = ""; + // hexString-->byte[] + byte[] keyData = ByteUtils.fromHexString(hexKey); + // hexString-->byte[] + byte[] cipherData = ByteUtils.fromHexString(cipherText); + // 解密 + byte[] srcData = decrypt_Ecb_Padding(keyData, cipherData); + // byte[]-->String + decryptStr = new String(srcData, ENCODING); + return decryptStr; + } + + /** + * 解密 + * @explain + * @param key + * @param cipherText + * @return + * @throws Exception + */ + public static byte[] decrypt_Ecb_Padding(byte[] key, byte[] cipherText) throws Exception { + Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key); + return cipher.doFinal(cipherText); + } + + /** + * 校验加密前后的字符串是否为同一数据 + * @explain + * @param hexKey + * 16进制密钥(忽略大小写) + * @param cipherText + * 16进制加密后的字符串 + * @param paramStr + * 加密前的字符串 + * @return 是否为同一数据 + * @throws Exception + */ + public static boolean verifyEcb(String hexKey, String cipherText, String paramStr) throws Exception { + // 用于接收校验结果 + boolean flag = false; + // hexString-->byte[] + byte[] keyData = ByteUtils.fromHexString(hexKey); + // 将16进制字符串转换成数组 + byte[] cipherData = ByteUtils.fromHexString(cipherText); + // 解密 + byte[] decryptData = decrypt_Ecb_Padding(keyData, cipherData); + // 将原字符串转换成byte[] + byte[] srcData = paramStr.getBytes(ENCODING); + // 判断2个数组是否一致 + flag = Arrays.equals(decryptData, srcData); + return flag; + } +} diff --git a/service/src/main/resources/application.yml b/service/src/main/resources/application.yml new file mode 100644 index 0000000..bfeffbf --- /dev/null +++ b/service/src/main/resources/application.yml @@ -0,0 +1,7 @@ +# 端口号 +server: + port: 8686 + +# 是否开启加密 +encrypt: + enabled: true diff --git a/web/.browserslistrc b/web/.browserslistrc new file mode 100644 index 0000000..214388f --- /dev/null +++ b/web/.browserslistrc @@ -0,0 +1,3 @@ +> 1% +last 2 versions +not dead diff --git a/web/.editorconfig b/web/.editorconfig new file mode 100644 index 0000000..7053c49 --- /dev/null +++ b/web/.editorconfig @@ -0,0 +1,5 @@ +[*.{js,jsx,ts,tsx,vue}] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/web/.env.development b/web/.env.development new file mode 100644 index 0000000..10ca0be --- /dev/null +++ b/web/.env.development @@ -0,0 +1,4 @@ +VUE_APP_BASE_API = '/dev-api' + +# 路由懒加载 +VUE_CLI_BABEL_TRANSPILE_MODULES = true diff --git a/web/.env.production b/web/.env.production new file mode 100644 index 0000000..81ba185 --- /dev/null +++ b/web/.env.production @@ -0,0 +1 @@ +VUE_APP_BASE_API = '/prod-api' diff --git a/web/.eslintrc.js b/web/.eslintrc.js new file mode 100644 index 0000000..2c6a7fa --- /dev/null +++ b/web/.eslintrc.js @@ -0,0 +1,17 @@ +module.exports = { + root: true, + env: { + node: true + }, + extends: [ + 'plugin:vue/essential', + '@vue/standard' + ], + parserOptions: { + parser: 'babel-eslint' + }, + rules: { + 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off' + } +} diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..403adbc --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules +/dist + + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/web/babel.config.js b/web/babel.config.js new file mode 100644 index 0000000..e955840 --- /dev/null +++ b/web/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + '@vue/cli-plugin-babel/preset' + ] +} diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..2fe8f5b --- /dev/null +++ b/web/package.json @@ -0,0 +1,40 @@ +{ + "name": "code", + "version": "0.1.0", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint", + "start": "node index.js", + "server": "nodemon index.js --ignore client" + }, + "dependencies": { + "axios": "^0.24.0", + "core-js": "^3.6.5", + "element-ui": "^2.13.2", + "es6-promise": "^4.2.8", + "sm-crypto": "^0.3.7", + "vue": "^2.6.11", + "vue-router": "^3.2.0", + "vuex": "^3.4.0" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "~4.5.0", + "@vue/cli-plugin-eslint": "~4.5.0", + "@vue/cli-plugin-router": "~4.5.0", + "@vue/cli-plugin-vuex": "~4.5.0", + "@vue/cli-service": "~4.5.0", + "@vue/eslint-config-standard": "^5.1.2", + "babel-eslint": "^10.1.0", + "eslint": "^6.7.2", + "eslint-plugin-import": "^2.20.2", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.0", + "eslint-plugin-vue": "^6.2.2", + "less": "^3.0.4", + "less-loader": "^5.0.0", + "vue-template-compiler": "^2.6.11" + } +} diff --git a/web/public/favicon.ico b/web/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevRz$KlnO_H2c< z(XX#lPuW_%H#Q+c&(nRyX1-Ia dKR-%$4FYC0fsCmL9ky3 zKpxyjd^JFR+vg2!=HWf}2Z?@Td`0EG`kU?{8zKrvtsm)|7>pPk9nu@2^z96aU2<#` z2QhvH5w&V;wER?mopu+nqu*n8p~(%Q kwSs&*0eJwa zMXR05`OSFpfyRb! Y_+H@O%Y z0=K^y6B8Gcbl?SA)qMP3Z+=C(?8zL@=74R=EVnE?vY!1BQy2@q*RUgRx4yJ$k}MnL zs!?74QciNb-LcG*&o<9=DSL>1n}ZNd)w1z3-0Pd^4ED1{qd=9|!!N?xnXjM!EuylY z5=!H>&hSofh8V?Jofyd!h`xDI1fYAuV(sZwwN~{$a}MX^=+0TH*SFp$vyxmUv7C*W zv^3Gl0+eTFgBi3FVD;$nhcp)ka*4gSskYIqQ&+M}xP9yLAkWzBI^I%zR^l1e?bW_6 zIn{mo{dD=)9@V?s^fa55jh78rP*Ze<3`tRCN4*mpO$@7a^*2B*7N_|A(Ve2VB|)_o z$=#_=aBkhe(ifX}MLT()@5? OV+~7cXC3r!%{QJxriXo9I%*3q4KT4Xxzyd{ z9;_%=W%q!Vw$Z7F3lUnY+1HZ*lO;4;VR2+i4+D(m#01OYq|L_fbnT;KN<^dkkCwtd zF7n+O7KvAw8c`JUh6LmeIrk4`F3o|AagKSMK3))_5Cv~y2Bb2!Ibg9BO7Vkz?pAYX zoI=B}+$R22&IL`NCYUYjrdhwjnM x_v=-Qcx-jmtN>!Zqf|n1^SWrHy zK|MwJ?Z#^>)rfT5YSY{qjZ&`Fjd;^vv&gF-Yj6$9-Dy$<6zeP4s+78gS2|t%Z309b z0^fp~ue_}i`U9j!<|qF92_3oB09NqgAoehQ`)<)dSfKoJl_A6Ec#*Mx9Cpd-p#$Ez z={AM*r-bQs6*z$!*V A4|QE7bf@-4vb?Q+pPKLkY2{yKsw{&udv_2v8{Dbd zm~8VAv!G~s)`O3|Q6vFUV%8%+?ZSVUa(;fhPNg#vab@J*9XE4#D%)$UU-T5`fwjz! z6&gA^`OGu6aUk{l*h9eB?opVdrHK>Q@U>&JQ_2pR%}TyOXGq_6s56_`U(WoOaAb+K zXQr#6H}>a-GYs9^bG P2Y&hSP5gEtW+GVC4=wy0wQk=~%CSXj=GH6q z-T#s!BV`xZVxm{~jr_ezYRpqqIcXC=Oq`b{lu`Rt(IYr4B91hhVC?yg{ol4WUr3v9 zOAk2LG>CIECZ-WIs0$N}F#eoIUEtZudc7DPYIjzGqDLWk_A4#( LgacooD z2K4IWs@N`Bddm-{%oy}!k0^i6Yh)uJ1S*90>|bm3TOZxcV|ywHUb(+CeX-o1|LTZM zwU>dY3R&U)T(}5#Neh?-CWT~@{6Ke@sI)uSuzoah8COy)w)B)aslJmp`WUcjdia-0 zl2Y}&L~XfA`uYQboAJ1;J{XLhYjH){cObH3FDva+^8ioOQy%Z=xyjGLmWMrzfFoH; zEi3AG`_v+%)&lDJE;iJWJDI@-X9K5O)LD~j*PBe(wu+|%ar~C+LK1+-+lK =t# z+Xc+J7qp~5q=B~rD!x78)?1+KUIbYr^5rcl&tB-cTtj+e%{gpZZ4G~6r15+d|J(ky zjg@@UzMW0k9@S#W(1H{u;Nq(7llJbq;;4t$awM;l&(2s+$l!Ay9^Ge|34CVhr7|BG z?dAR83smef^frq9V(OH+a+ki#q&-7TkWfFM=5bsGbU(8mC;>QTCWL5ydz9s6k@?+V zcjiH`VI=59P-(-DWXZ~5DH>B^_H~;4$)KUhnmGo*G!Tq8^LjfUDO)lASN*=#AY_yS zqW9UX(VOCO&p@kHdUUgsBO0KhXxn1sprK5h8}+>IhX(nSXZKwlNsjk^M|RAaqmCZB zHBol OHYBas@&{PT=R+?d8pZu zUHfyucQ`(umXSW7o?HQ3H21M`ZJal+%*)SH1B1j6rxTlG3hx1IGJN^M7{$j(9V;MZ zRKybgVuxKo#XVM+?*yTy{W+XHaU5Jbt-UG33x{u(N-2wmw;zzPH&4DE103HV@ER86 z|FZEmQb|&1s5#`$4!Cm}&`^{(4V}OP$bk`}v6q6rm;P!H)W|2i^e{7lTk2W@jo_9q z*aw|U7#+g59Fv(5qI`#O-qPj#@_P>PC#I(GSp3DLv7x-dmYK=C7lPF8a)bxb=@)B1 zUZ`EqpXV2dR}B&r`uM}N(TS99ZT0UB%IN|0H%DcVO#T%L_chrgn#m6%x4KE*IMfjX zJ%4veCEqbXZ`H`F_+fELMC@wuy_ch%t*+Z+1I}wN#C+dRrf2X{1C8=yZ_%Pt6wL_~ zZ2NN-hXOT4P4n$QFO7yYHS-4wF1Xfr-meG9Pn;uK51?hfel`d38k{W)F*|gJLT2#T z<~>spMu4(mul-8Q3*pf=N4DcI)zzjqAgbE2eOT7~&f1W3VsdD44Ffe;3mJp-V@8UC z)|qnPc12o~$X-+U@L_lWqv-RtvB~%hLF($%Ew5w>^NR82qC_0F B z)=hP1-OEx?lLi#jnLzH}a;Nvr@JDO-zQWd}#k^an$Kwml;MrD&)sC5b`s0ZkVyPkb zt}-jOq^%_9>YZe7Y}PhW{a)c39G`kg(P4@kxjcYfgB4XOOcmezdUI7j-!gs7oAo2o zx(Ph{G+YZ`a%~kzK!HTAA5NXE-7vOFRr5oqY$rH>WI6SFvWmahFav!CfRMM3%8J&c z*p+%|-fNS_@QrFr(at!JY9jCg9F-%5{nb5Bo~z@Y9m&SHYV`49GAJjA5h~h4(G!Se zZmK{Bo7ivCfvl}@A-ptkFGcWXAzj3xfl{evi-OG(TaCn1FAHxRc{}B|x+Ua1D=I6M z!C^ZIvK6aS_c&(=OQDZfm>O`Nxsw{ta&yiYPA~@e#c%N>>#rq)k6Aru-qD4(D^v)y z*>Rs;YUbD1S8^D(ps6Jbj0K3wJw>L4m)0e(6Pee3Y?gy9i0^bZO?$*sv+xKV?WBlh zAp*;v6w!a8;A7sLB*g-^<$Z4L7|5jXxxP1}hQZ<55f9<^KJ>^mKlWSGaLcO0=$jem zWyZkRwe~u{{tU63DlCaS9$Y4CP4f?+wwa(&1ou)b>72yd rFvm`R j-0`kBJgK@nd(*Eh!(NC{F-@=FnF&Y!q`7){YsLLHf0_B6aHc# z>WIuHTyJwIH{BJ4)2RtEauC7Yq7Cytc|S )4^*t8Va3HR zg=~sN^tp9re@w=GTx$;zOWMjcg-7X3Wk^N$n;&Kf1RgVG2}2L-(0o)54C509C&77i zrjSi{X*WV=%C17((N^6R4Ya*4#6s_L99RtQ>m(%#nQ#wrRC8Y%yxkH;d!MdY+Tw@r zjpSnK`;C-U{ATcgaxoEpP0Gf+tx);buOM lK=01D|J+ROu37qc*rD(w`#O=3*O*w9?biwNoq3WN1`&Wp8TvKj3C z3HR9ssH7a&Vr<6waJrUzdLg!ieYz%U^bmpn%;(V%%ugMk92&?_XX1K@mwnVSE6!&%P%Wdi7_h`CpScvspMx?N zQUR>oadnG17#hNc$pkTp+9 lW+MBKHRZ~7 4XWUryd)4yd zj98$%XmIL4(9OnoeO5Fnyn&fpQ9b0h4e6EHHw*l68j;>(ya`g^S&y2{O8U>1*>4zR zq*WSI_2o$CHQ?x0!wl9bpx|Cm2+kFMR)oMud1%n2=qn5nE&t@Fgr#=Zv2?}wtEz^T z9rrj=?I H*qI5{G@Rn&}^Z{+TW}mQe b9=8b<_a`&Cm#n%n~ zU47MvCBsdXFB1+adOO)03+nczfWa#vwk #r{o{dF)QWya9v2nv43Zp3%Ps}($lA02*_g25t;|T{A5snSY?3A zrRQ~(Ygh_ebltHo1VC bJb*eOAr;4cnlXLvI>*$-#AVsGg6B1r7@;g^L zFlJ_th0vxO7;-opU@WAFe;<}?!2q?RBrFK5U{ *ai@NLKZ^};Ul}beukveh?TQn;$%9=R+DX07m82gP$=}Uo_%&ngV`}Hyv8g{u z3SWzTGV|cwQuFIs7ZDOqO_fGf8Q`8MwL}eUp>q?4eqCmOTcwQuXtQckPy|4F1on8l zP*h>d+cH#XQf|+6c|S{7SF(Lg>bR~l(0uY?O{OEVlaxa5@e%T&xju=o1`=OD#qc16 zSvyH*my(dcp6~VqR;o(#@m44Lug@~_qw+HA=mS#Z^ 4reBy8iV?H~I;{LQWk3aKK8$bLRyt$g?- h(App) +}).$mount('#app') diff --git a/web/src/router/index.js b/web/src/router/index.js new file mode 100644 index 0000000..18e1abc --- /dev/null +++ b/web/src/router/index.js @@ -0,0 +1,34 @@ +import Vue from 'vue' +import VueRouter from 'vue-router' + +Vue.use(VueRouter) + +const routes = [ + { + path: '/', + name: 'index', + component: () => import('../views/Index') + } +] + +const router = new VueRouter({ + routes +}) + +// 导航守卫 +// 使用 router.beforeEach 注册一个全局前置守卫,判断用户是否登陆 +router.beforeEach((to, from, next) => { + if (to.path === '/login') { + next(); + } else { + let token = localStorage.getItem('Authorization'); + + if (token === 'null' || token === '') { + next('/login'); + } else { + next(); + } + } +}); + +export default router diff --git a/web/src/store/index.js b/web/src/store/index.js new file mode 100644 index 0000000..332b916 --- /dev/null +++ b/web/src/store/index.js @@ -0,0 +1,15 @@ +import Vue from 'vue' +import Vuex from 'vuex' + +Vue.use(Vuex) + +export default new Vuex.Store({ + state: { + }, + mutations: { + }, + actions: { + }, + modules: { + } +}) diff --git a/web/src/utils/request.js b/web/src/utils/request.js new file mode 100644 index 0000000..64afc74 --- /dev/null +++ b/web/src/utils/request.js @@ -0,0 +1,102 @@ +import axios from 'axios' +import { + sm4KeyGenerator, + getRequestKey, + encryptRequestData, + getResponseJson +} from '@/utils/sm' + +// sm4秘钥 +const sm4Key = sm4KeyGenerator() +// 是否加密 +const isAddSm = true +// sm4Key数组 +const sm4KeyArr = [] + +axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' +// 创建axios实例 +const service = axios.create({ + // axios中请求配置有baseURL选项,表示请求URL公共部分 + baseURL: process.env.VUE_APP_BASE_API, + // 超时 + timeout: 10000 +}) +// request拦截器 +service.interceptors.request.use(config => { + // 将秘钥加密后放到请求头中 + config.headers.RequestKey = getRequestKey(sm4Key, false) // 请求key + // get请求映射params参数 + if (config.method === 'get' && config.params) { + let url = config.url + '?' + for (const propName of Object.keys(config.params)) { + const value = config.params[propName] + const part = encodeURIComponent(propName) + '=' + if (value !== null && typeof (value) !== 'undefined') { + if (typeof value === 'object') { + for (const key of Object.keys(value)) { + const params = propName + '[' + key + ']' + const subPart = encodeURIComponent(params) + '=' + url += subPart + encodeURIComponent(value[key]) + '&' + } + } else { + url += part + encodeURIComponent(value) + '&' + } + } + } + url = url.slice(0, -1) + config.params = {} + config.url = url + } else if (config.method === 'post') { + if (isAddSm && config.url.indexOf('upload') === -1) { + config.data = encryptRequestData(config.data, sm4Key, config.method) + const obj = {} + obj.url = config.url + obj.sm4keyNum = sm4Key + obj.cis_req_params = config.data.cis_req_params + sm4KeyArr.push(obj) + } + } + return config +}, error => { + console.log(error) + Promise.reject(error) +}) + +// 响应拦截器 +service.interceptors.response.use(res => { + // 未设置状态码则默认成功状态 + const code = res.data.code || 200 + // 返回值解密 + if (isAddSm) { + if (res.config.method !== 'OPTIONS') { + let i + let myKey + if (res.config.method === 'post') { + for (const item in sm4KeyArr) { + if (sm4KeyArr[item].cis_req_params === JSON.parse(res.config.data).cis_req_params) { + myKey = sm4KeyArr[item].sm4keyNum + i = item + } + } + if (code === 200) { + res.data = getResponseJson(res.data, myKey) + } + sm4KeyArr.splice(i, 1) + } + } else { + return + } + } + if (code !== 200) { + // eslint-disable-next-line prefer-promise-reject-errors + return Promise.reject('error') + } else { + return res.data + } +}, +error => { + console.log('err' + error) + return Promise.reject(error) +}) + +export default service diff --git a/web/src/utils/sm.js b/web/src/utils/sm.js new file mode 100644 index 0000000..cf25b15 --- /dev/null +++ b/web/src/utils/sm.js @@ -0,0 +1,87 @@ +// 引入sm +const sm = require('sm-crypto') + +// sm2公钥 +const sm2Key = '04813d4d97ad31bd9d18d785f337f683233099d5abed09cb397152d50ac28cc0ba43711960e811d90453db5f5a9518d660858a8d0c57e359a8bf83427760ebcbba' + +/** + * 生成SMKey + * @returns {string} + */ +export function sm4KeyGenerator () { + const sm4KeySeed = '123456789abcdef' + const keySize = 32 + let sm4key = '' + while (sm4key.length < keySize) { + const randomIndex = Math.floor(Math.random() * 100) % 16 + sm4key += sm4KeySeed.charAt(randomIndex) + } + return sm4key +} + +/** + * 生成SM2随机请求Key + * @param sm4key + * @param isStream + * @returns {*} + */ +export function getRequestKey (sm4key, isStream) { + let key = sm4key + '-' + Date.now() + if (isStream) { + key = '1-' + key + } else { + key = '0-' + key + } + // 1 - C1C3C2,0 - C1C2C3,默认为1 + const cipherMode = 0 + // 解密结果 + // sm.sm2.doDecrypt(sm.sm2.doEncrypt(key, publicKey, cipherMode), privateKey, cipherMode); + // 加密结果 + return sm2Encrypt(key, sm2Key, cipherMode) +} + +/** + * 对请求参数加密 + * */ +export function encryptRequestData (data, sm4key, type) { + let params + let obj + if (!data) { + if (type === 'get') { + params = 'tp=' + Date.now() + } else { + data = { + tp: Date.now() + } + params = JSON.stringify(data) + } + obj = { + cis_req_params: sm.sm4.encrypt(params, sm4key), + cis_fingerprint: sm.sm3(params) + } + } else { + if (type === 'get') { + params = Object.keys(data).map(function (key) { + return key + '=' + data[key] + }).join('&') + } else { + params = JSON.stringify(data) + } + obj = { + cis_req_params: sm.sm4.encrypt(params, sm4key), + cis_fingerprint: sm.sm3(params) + } + } + return obj +} + +/** + * 返回数据解密 + * @param data + * @param sm4key + * @returns {any} + */ +export function getResponseJson (data, sm4key) { + const result = sm.sm4.decrypt(data, sm4key) + return JSON.parse(result) +} diff --git a/web/src/views/Index.vue b/web/src/views/Index.vue new file mode 100644 index 0000000..0245689 --- /dev/null +++ b/web/src/views/Index.vue @@ -0,0 +1,105 @@ + + ++ + + + + diff --git a/web/vue.config.js b/web/vue.config.js new file mode 100644 index 0000000..9d43bf1 --- /dev/null +++ b/web/vue.config.js @@ -0,0 +1,65 @@ +module.exports = { + // 基本路径 + publicPath: '/', + // 输出文件目录 + outputDir: 'dist', + // eslint-loader 是否在保存的时候检查 + lintOnSave: false, + // use the full build with in-browser compiler? + // https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only + runtimeCompiler: false, + // webpack配置 + // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md + chainWebpack: () => {}, + configureWebpack: () => {}, + // vue-loader 配置项 + // https://vue-loader.vuejs.org/en/options.html + // vueLoader: {}, + // 生产环境是否生成 sourceMap 文件 + productionSourceMap: false, + // css相关配置 + /* css: { + // 是否使用css分离插件 ExtractTextPlugin + extract: true, + // 开启 CSS source maps? + sourceMap: false, + // css预设器配置项 + loaderOptions: {}, + // 启用 CSS modules for all css / pre-processor files. + modules: false + }, */ + // use thread-loader for babel & TS in production build + // enabled by default if the machine has more than 1 cores + parallel: require('os').cpus().length > 1, + // 是否启用dll + // See https://github.com/vuejs/vue-cli/blob/dev/docs/cli-service.md#dll-mode + // dll: false, + // PWA 插件相关配置 + // see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa + pwa: {}, + // webpack-dev-server 相关配置 + devServer: { + // open: process.platform === 'darwin', + // 将服务启动后默认打开浏览器 + open: true, + host: '0.0.0.0', + port: 8080, + https: false, + hotOnly: false, + proxy: { + // detail: https://cli.vuejs.org/config/#devserver-proxy + [process.env.VUE_APP_BASE_API]: { + target: 'http://localhost:8686', + changeOrigin: true, + pathRewrite: { + ['^' + process.env.VUE_APP_BASE_API]: '' + } + } + }, + before: app => {} + }, + // 第三方插件配置 + pluginOptions: { + // ... + } +}+ ++ ++ ++ ++ ++ + + ++ 提交 +