mirror of https://github.com/longtai-cn/hippo4j
Encrypted transmission of login password (#1316)
* feat(login): #1300 Encrypted transmission of login password * feat(login): #1300 Modify the comments to English * ref(login): #1300 Restore static resources --------- Co-authored-by: limingwei <limingwei@century-cn.com> Co-authored-by: Serenity <SerenitySir@outlook.com>pull/1320/head
parent
dd2c27ba3c
commit
a9ca0a7b84
@ -1,126 +1,155 @@
|
||||
import { login } from '@/api/user';
|
||||
import { getToken, setToken, removeToken } from '@/utils/auth';
|
||||
import router, { resetRouter } from '@/router';
|
||||
import {login} from '@/api/user';
|
||||
import {getToken, removeToken, setToken} from '@/utils/auth';
|
||||
import router, {resetRouter} from '@/router';
|
||||
import {Buffer} from 'buffer'
|
||||
import crypto from 'crypto'
|
||||
|
||||
const state = {
|
||||
token: getToken(),
|
||||
name: '',
|
||||
avatar: '',
|
||||
introduction: '',
|
||||
roles: [],
|
||||
token: getToken(),
|
||||
name: '',
|
||||
avatar: '',
|
||||
introduction: '',
|
||||
roles: [],
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
SET_TOKEN: (state, token) => {
|
||||
state.token = token;
|
||||
},
|
||||
SET_INTRODUCTION: (state, introduction) => {
|
||||
state.introduction = introduction;
|
||||
},
|
||||
SET_NAME: (state, name) => {
|
||||
state.name = name;
|
||||
},
|
||||
SET_AVATAR: (state, avatar) => {
|
||||
state.avatar = avatar;
|
||||
},
|
||||
SET_ROLES: (state, roles) => {
|
||||
state.roles = roles;
|
||||
},
|
||||
SET_TOKEN: (state, token) => {
|
||||
state.token = token;
|
||||
},
|
||||
SET_INTRODUCTION: (state, introduction) => {
|
||||
state.introduction = introduction;
|
||||
},
|
||||
SET_NAME: (state, name) => {
|
||||
state.name = name;
|
||||
},
|
||||
SET_AVATAR: (state, avatar) => {
|
||||
state.avatar = avatar;
|
||||
},
|
||||
SET_ROLES: (state, roles) => {
|
||||
state.roles = roles;
|
||||
},
|
||||
};
|
||||
|
||||
const actions = {
|
||||
// user login
|
||||
login({ commit }, userInfo) {
|
||||
const { username, password } = userInfo;
|
||||
return new Promise((resolve, reject) => {
|
||||
login({ username: username.trim(), password: password, rememberMe: 1 })
|
||||
.then((response) => {
|
||||
const { data } = response;
|
||||
const { roles } = response;
|
||||
commit('SET_TOKEN', data);
|
||||
localStorage.setItem('roles', JSON.stringify(roles));
|
||||
localStorage.setItem('USER_ROLE', roles[0]);
|
||||
setToken(data);
|
||||
resolve();
|
||||
})
|
||||
.catch((error) => {
|
||||
alert('登录失败');
|
||||
reject(error);
|
||||
// user login
|
||||
login({commit}, userInfo) {
|
||||
const {username, password} = userInfo;
|
||||
return new Promise((resolve, reject) => {
|
||||
let key = actions.genKey();
|
||||
let encodePassword = actions.encrypt(password, key)
|
||||
key = key.split("").reverse().join("")
|
||||
login({username: username.trim(), password: encodePassword, tag: key, rememberMe: 1})
|
||||
.then((response) => {
|
||||
const {data} = response;
|
||||
const {roles} = response;
|
||||
commit('SET_TOKEN', data);
|
||||
localStorage.setItem('roles', JSON.stringify(roles));
|
||||
localStorage.setItem('USER_ROLE', roles[0]);
|
||||
setToken(data);
|
||||
resolve();
|
||||
})
|
||||
.catch((error) => {
|
||||
// alert('登录失败');
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// get user info
|
||||
getInfo({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const data = {};
|
||||
data.roles = JSON.parse(localStorage.getItem('roles'));
|
||||
commit('SET_ROLES', data.roles);
|
||||
resolve(data);
|
||||
});
|
||||
},
|
||||
|
||||
// user logout
|
||||
logout({ commit, state }) {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// logout(state.token).then(() => {
|
||||
// commit('SET_TOKEN', '')
|
||||
// commit('SET_ROLES', [])
|
||||
// removeToken()
|
||||
// resetRouter()
|
||||
// resolve()
|
||||
// }).catch(error => {
|
||||
// reject(error)
|
||||
// })
|
||||
// })
|
||||
return new Promise((resolve) => {
|
||||
commit('SET_TOKEN', '');
|
||||
commit('SET_ROLES', []);
|
||||
removeToken();
|
||||
resetRouter();
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
|
||||
// remove token
|
||||
resetToken({ commit }) {
|
||||
return new Promise((resolve) => {
|
||||
commit('SET_TOKEN', '');
|
||||
commit('SET_ROLES', []);
|
||||
removeToken();
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
|
||||
// dynamically modify permissions
|
||||
changeRoles({ commit, dispatch }, role) {
|
||||
return new Promise(async (resolve) => {
|
||||
const token = role + '-token';
|
||||
|
||||
commit('SET_TOKEN', token);
|
||||
setToken(token);
|
||||
|
||||
const { roles } = await dispatch('getInfo');
|
||||
|
||||
resetRouter();
|
||||
|
||||
// generate accessible routes map based on roles
|
||||
const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true });
|
||||
|
||||
// dynamically add accessible routes
|
||||
router.addRoutes(accessRoutes);
|
||||
|
||||
// reset visited views and cached views
|
||||
dispatch('tagsView/delAllViews', null, { root: true });
|
||||
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
// get user info
|
||||
getInfo({commit, state}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const data = {};
|
||||
data.roles = JSON.parse(localStorage.getItem('roles'));
|
||||
commit('SET_ROLES', data.roles);
|
||||
resolve(data);
|
||||
});
|
||||
},
|
||||
|
||||
// user logout
|
||||
logout({commit, state}) {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// logout(state.token).then(() => {
|
||||
// commit('SET_TOKEN', '')
|
||||
// commit('SET_ROLES', [])
|
||||
// removeToken()
|
||||
// resetRouter()
|
||||
// resolve()
|
||||
// }).catch(error => {
|
||||
// reject(error)
|
||||
// })
|
||||
// })
|
||||
return new Promise((resolve) => {
|
||||
commit('SET_TOKEN', '');
|
||||
commit('SET_ROLES', []);
|
||||
removeToken();
|
||||
resetRouter();
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
|
||||
// remove token
|
||||
resetToken({commit}) {
|
||||
return new Promise((resolve) => {
|
||||
commit('SET_TOKEN', '');
|
||||
commit('SET_ROLES', []);
|
||||
removeToken();
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
|
||||
// dynamically modify permissions
|
||||
changeRoles({commit, dispatch}, role) {
|
||||
return new Promise(async (resolve) => {
|
||||
const token = role + '-token';
|
||||
|
||||
commit('SET_TOKEN', token);
|
||||
setToken(token);
|
||||
|
||||
const {roles} = await dispatch('getInfo');
|
||||
|
||||
resetRouter();
|
||||
|
||||
// generate accessible routes map based on roles
|
||||
const accessRoutes = await dispatch('permission/generateRoutes', roles, {root: true});
|
||||
|
||||
// dynamically add accessible routes
|
||||
router.addRoutes(accessRoutes);
|
||||
|
||||
// reset visited views and cached views
|
||||
dispatch('tagsView/delAllViews', null, {root: true});
|
||||
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
genKey() {
|
||||
let chars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
let result = '';
|
||||
for (let i = 16; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
|
||||
return result;
|
||||
},
|
||||
encrypt(msg, key) {
|
||||
try {
|
||||
let pwd = Buffer.from(key)
|
||||
let iv = crypto.randomBytes(12)
|
||||
let cipher = crypto.createCipheriv('aes-128-gcm', pwd, iv)
|
||||
let enc = cipher.update(msg, 'utf8', 'base64')
|
||||
enc += cipher.final('base64')
|
||||
let tags = cipher.getAuthTag()
|
||||
enc = Buffer.from(enc, 'base64')
|
||||
let totalLength = iv.length + enc.length + tags.length
|
||||
let bufferMsg = Buffer.concat([iv, enc, tags], totalLength)
|
||||
return bufferMsg.toString('base64')
|
||||
} catch (e) {
|
||||
console.log("Encrypt is error", e)
|
||||
return null
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions,
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions,
|
||||
};
|
||||
|
@ -0,0 +1,92 @@
|
||||
package cn.hippo4j.auth.toolkit;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* AES encryption and decryption algorithm tool class
|
||||
*
|
||||
* @author <a href="mailto:SerenitySir@outlook.com">Serenity</a>
|
||||
* @date 2023/5/21 14:37
|
||||
* @since JDK1.8+
|
||||
*/
|
||||
@UtilityClass
|
||||
public class AESUtil {
|
||||
|
||||
private static final String AES_GCM_CIPHER = "AES/GCM/PKCS5Padding";
|
||||
|
||||
/**
|
||||
* encrypt
|
||||
*
|
||||
* @param data Content that needs to be encrypted
|
||||
* @param key Encrypt the password
|
||||
* @return byte[]
|
||||
*/
|
||||
public static byte[] encrypt(byte[] data, byte[] key) throws GeneralSecurityException {
|
||||
SecretKeySpec sKeySpec = new SecretKeySpec(key, "AES");
|
||||
Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);
|
||||
byte[] iv = cipher.getIV();
|
||||
byte[] encryptData = cipher.doFinal(data);
|
||||
byte[] message = new byte[12 + data.length + 16];
|
||||
System.arraycopy(iv, 0, message, 0, 12);
|
||||
System.arraycopy(encryptData, 0, message, 12, encryptData.length);
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* decrypt
|
||||
*
|
||||
* @param data The content to be decrypted
|
||||
* @param key Decryption key
|
||||
* @return byte[]
|
||||
*/
|
||||
public static byte[] decrypt(byte[] data, byte[] key) throws GeneralSecurityException{
|
||||
GCMParameterSpec iv = new GCMParameterSpec(128, data, 0, 12);
|
||||
Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER);
|
||||
SecretKey key2 = new SecretKeySpec(key, "AES");
|
||||
cipher.init(Cipher.DECRYPT_MODE, key2, iv);
|
||||
return cipher.doFinal(data, 12, data.length - 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* encrypt
|
||||
*
|
||||
* @param data Content that needs to be encrypted
|
||||
* @param key Encrypt the password
|
||||
* @return String
|
||||
*/
|
||||
public static String encrypt(String data, String key) throws GeneralSecurityException {
|
||||
byte[] valueByte = encrypt(data.getBytes(StandardCharsets.UTF_8), key.getBytes(StandardCharsets.UTF_8));
|
||||
return Base64.getEncoder().encodeToString(valueByte);
|
||||
}
|
||||
|
||||
/**
|
||||
* decrypt
|
||||
*
|
||||
* @param data The content to be decrypted is a base64 string
|
||||
* @param key Decryption key
|
||||
* @return String
|
||||
*/
|
||||
public static String decrypt(String data, String key) throws GeneralSecurityException {
|
||||
byte[] originalData = Base64.getDecoder().decode(data.getBytes());
|
||||
byte[] valueByte = decrypt(originalData, key.getBytes(StandardCharsets.UTF_8));
|
||||
return new String(valueByte);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random string key
|
||||
*
|
||||
* @return The string key
|
||||
*/
|
||||
public static String generateRandomKey() {
|
||||
return IdWorker.get32UUID().substring(0, 16);
|
||||
}
|
||||
}
|
Loading…
Reference in new issue