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 {login} from '@/api/user';
|
||||||
import { getToken, setToken, removeToken } from '@/utils/auth';
|
import {getToken, removeToken, setToken} from '@/utils/auth';
|
||||||
import router, { resetRouter } from '@/router';
|
import router, {resetRouter} from '@/router';
|
||||||
|
import {Buffer} from 'buffer'
|
||||||
|
import crypto from 'crypto'
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
token: getToken(),
|
token: getToken(),
|
||||||
name: '',
|
name: '',
|
||||||
avatar: '',
|
avatar: '',
|
||||||
introduction: '',
|
introduction: '',
|
||||||
roles: [],
|
roles: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
SET_TOKEN: (state, token) => {
|
SET_TOKEN: (state, token) => {
|
||||||
state.token = token;
|
state.token = token;
|
||||||
},
|
},
|
||||||
SET_INTRODUCTION: (state, introduction) => {
|
SET_INTRODUCTION: (state, introduction) => {
|
||||||
state.introduction = introduction;
|
state.introduction = introduction;
|
||||||
},
|
},
|
||||||
SET_NAME: (state, name) => {
|
SET_NAME: (state, name) => {
|
||||||
state.name = name;
|
state.name = name;
|
||||||
},
|
},
|
||||||
SET_AVATAR: (state, avatar) => {
|
SET_AVATAR: (state, avatar) => {
|
||||||
state.avatar = avatar;
|
state.avatar = avatar;
|
||||||
},
|
},
|
||||||
SET_ROLES: (state, roles) => {
|
SET_ROLES: (state, roles) => {
|
||||||
state.roles = roles;
|
state.roles = roles;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
// user login
|
// user login
|
||||||
login({ commit }, userInfo) {
|
login({commit}, userInfo) {
|
||||||
const { username, password } = userInfo;
|
const {username, password} = userInfo;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
login({ username: username.trim(), password: password, rememberMe: 1 })
|
let key = actions.genKey();
|
||||||
.then((response) => {
|
let encodePassword = actions.encrypt(password, key)
|
||||||
const { data } = response;
|
key = key.split("").reverse().join("")
|
||||||
const { roles } = response;
|
login({username: username.trim(), password: encodePassword, tag: key, rememberMe: 1})
|
||||||
commit('SET_TOKEN', data);
|
.then((response) => {
|
||||||
localStorage.setItem('roles', JSON.stringify(roles));
|
const {data} = response;
|
||||||
localStorage.setItem('USER_ROLE', roles[0]);
|
const {roles} = response;
|
||||||
setToken(data);
|
commit('SET_TOKEN', data);
|
||||||
resolve();
|
localStorage.setItem('roles', JSON.stringify(roles));
|
||||||
})
|
localStorage.setItem('USER_ROLE', roles[0]);
|
||||||
.catch((error) => {
|
setToken(data);
|
||||||
alert('登录失败');
|
resolve();
|
||||||
reject(error);
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
// alert('登录失败');
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
},
|
||||||
},
|
|
||||||
|
|
||||||
// get user info
|
// get user info
|
||||||
getInfo({ commit, state }) {
|
getInfo({commit, state}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const data = {};
|
const data = {};
|
||||||
data.roles = JSON.parse(localStorage.getItem('roles'));
|
data.roles = JSON.parse(localStorage.getItem('roles'));
|
||||||
commit('SET_ROLES', data.roles);
|
commit('SET_ROLES', data.roles);
|
||||||
resolve(data);
|
resolve(data);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// user logout
|
// user logout
|
||||||
logout({ commit, state }) {
|
logout({commit, state}) {
|
||||||
// return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
// logout(state.token).then(() => {
|
// logout(state.token).then(() => {
|
||||||
// commit('SET_TOKEN', '')
|
// commit('SET_TOKEN', '')
|
||||||
// commit('SET_ROLES', [])
|
// commit('SET_ROLES', [])
|
||||||
// removeToken()
|
// removeToken()
|
||||||
// resetRouter()
|
// resetRouter()
|
||||||
// resolve()
|
// resolve()
|
||||||
// }).catch(error => {
|
// }).catch(error => {
|
||||||
// reject(error)
|
// reject(error)
|
||||||
// })
|
// })
|
||||||
// })
|
// })
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
commit('SET_TOKEN', '');
|
commit('SET_TOKEN', '');
|
||||||
commit('SET_ROLES', []);
|
commit('SET_ROLES', []);
|
||||||
removeToken();
|
removeToken();
|
||||||
resetRouter();
|
resetRouter();
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// remove token
|
// remove token
|
||||||
resetToken({ commit }) {
|
resetToken({commit}) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
commit('SET_TOKEN', '');
|
commit('SET_TOKEN', '');
|
||||||
commit('SET_ROLES', []);
|
commit('SET_ROLES', []);
|
||||||
removeToken();
|
removeToken();
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// dynamically modify permissions
|
// dynamically modify permissions
|
||||||
changeRoles({ commit, dispatch }, role) {
|
changeRoles({commit, dispatch}, role) {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
const token = role + '-token';
|
const token = role + '-token';
|
||||||
|
|
||||||
commit('SET_TOKEN', token);
|
commit('SET_TOKEN', token);
|
||||||
setToken(token);
|
setToken(token);
|
||||||
|
|
||||||
const { roles } = await dispatch('getInfo');
|
const {roles} = await dispatch('getInfo');
|
||||||
|
|
||||||
resetRouter();
|
resetRouter();
|
||||||
|
|
||||||
// generate accessible routes map based on roles
|
// generate accessible routes map based on roles
|
||||||
const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true });
|
const accessRoutes = await dispatch('permission/generateRoutes', roles, {root: true});
|
||||||
|
|
||||||
// dynamically add accessible routes
|
// dynamically add accessible routes
|
||||||
router.addRoutes(accessRoutes);
|
router.addRoutes(accessRoutes);
|
||||||
|
|
||||||
// reset visited views and cached views
|
// reset visited views and cached views
|
||||||
dispatch('tagsView/delAllViews', null, { root: true });
|
dispatch('tagsView/delAllViews', null, {root: true});
|
||||||
|
|
||||||
resolve();
|
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 {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state,
|
state,
|
||||||
mutations,
|
mutations,
|
||||||
actions,
|
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