傳輸密碼動態加密解密
這個模塊分離至上一篇api權限管理系統與前後端分離實踐,感覺那樣寫文章太長了找不到重點,分離出來要好點。
在用戶密碼登錄認證中,明文傳輸用戶輸入的密碼是不可取的。在沒有用https的情況下,這裏需要對用戶密碼加密傳輸,保證即使密碼泄露也不影響。
這裏的前後端加密解密下圖:
由於介紹的是動態加密解密傳輸信息方案,這裏並不會涉及之後的JWT簽發等。
下面是實現細節:
angular 前端發送get動態祕鑰請求後會對對象進行監聽,在回調函數裏獲取後端返回的祕鑰後再進行加密處理,之後再發送登錄請求。在angular我把請求服務化了,下面的代碼片段會有點凌亂。
// 調用獲取tokenKey祕鑰服務
this.loginService.getTokenKey().subscribe(
data => {
this.responseData = data;
if (this.responseData.data.tokenKey !== undefined) {
const tokenKey = this.responseData.data.tokenKey;
// 調用服務,發送認證請求
this.loginService.login(this.appId, this.password, tokenKey).subscribe(
data2 => {
// 認證成功返回jwt
this.responseData = data2;
if (this.responseData.meta.code === 1003 && this.responseData.data.jwt != null) {
this.authService.updateAuthorizationToken(this.responseData.data.jwt);
this.authService.updateUid(this.appId);
this.authService.updateUser(this.responseData.data.user);
this.router.navigateByUrl('/index');
} else {
this.msg = '用戶名密碼錯誤';
this.isDisabled = true;
}
},
error => {
console.error(error);
this.msg = error;
this.isDisabled = true;
}
);
}
}
);
@Injectable()
export class LoginService {
constructor(private httpUtil: HttpUtil) {
}
getTokenKey() {
const url = 'account/login?tokenKey=get';
// 先向後臺申請加密tokenKey tokenKey=get
// const getKeyParam = new HttpParams().set('tokenKey', 'get');
return this.httpUtil.get(url);
}
login(appId: string, password: string, tokenKey: string) {
const url = 'account/login';
tokenKey = CryptoJS.enc.Utf8.parse(tokenKey);
password = CryptoJS.enc.Utf8.parse(password);
password = CryptoJS.AES.encrypt(password, tokenKey, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7}).toString();
console.log(password);
const param = new HttpParams().append('appId', appId)
.append('password', password)
.append('methodName', 'login')
.append('timestamp', new Date().toUTCString());
return this.httpUtil.post(url, param);
}
}
後端是在一個filter中對登錄註冊請求進行攔截,判斷其是正常登錄註冊還是獲取動態加密祕鑰請求,正常認證就走shiro,判斷爲獲取祕鑰則生成16隨機碼默認AES加密祕鑰爲約定16位,小於16位會報錯
,將祕鑰以<遠程IP,祕鑰>的
// 判斷若爲獲取登錄註冊加密動態祕鑰請求
if (isPasswordTokenGet(request)) {
//動態生成祕鑰,redis存儲祕鑰供之後祕鑰驗證使用,設置有效期5秒用完即丟棄
String tokenKey = CommonUtil.getRandomString(16);
try {
redisTemplate.opsForValue().set("PASSWORD_TOKEN_KEY_"+request.getRemoteAddr().toUpperCase(),tokenKey,5, TimeUnit.SECONDS);
// 動態祕鑰response返回給前端
Message message = new Message();
message.ok(1000,"issued tokenKey success")
.addData("tokenKey",tokenKey);
RequestResponseUtil.responseWrite(JSON.toJSONString(message),response);
}catch (Exception e) {
LOGGER.warn(e.getMessage(),e);
// 動態祕鑰response返回給前端
Message message = new Message();
message.ok(1000,"issued tokenKey fail");
RequestResponseUtil.responseWrite(JSON.toJSONString(message),response);
}
return false;
}
// 創建認證信息,其中就有包括獲取redis中對應IP的動態祕鑰
private AuthenticationToken createPasswordToken(ServletRequest request) {
Map<String ,String> map = RequestResponseUtil.getRequestParameters(request);
String appId = map.get("appId");
String timestamp = map.get("timestamp");
String password = map.get("password");
String host = request.getRemoteAddr();
String tokenKey = redisTemplate.opsForValue().get("PASSWORD_TOKEN_KEY_"+host.toUpperCase());
return new PasswordToken(appId,password,timestamp,host,tokenKey);
}
效果展示
持續更新。。。。。。
分享一波阿里雲代金券快速上雲
轉載請註明 from tomsun28