這個模塊分離至項目api權限管理系統與先後端分離實踐,感受那樣寫文章太長了找不到重點,分離出來要好點。html
在用戶密碼登陸認證中,明文傳輸用戶輸入的密碼是不可取的。在沒有用https的狀況下,這裏須要對用戶密碼加密傳輸,保證即便密碼泄露也不影響。 前端
這裏的先後端加密解密下圖: git
因爲介紹的是動態加密解密傳輸信息方案,這裏並不會涉及以後的JWT簽發等。 github
下面是實現細節:
angular 前端發送get動態祕鑰請求後會對對象進行監聽,在回調函數裏獲取後端返回的祕鑰後再進行加密處理,以後再發送登陸請求。在angular我把請求服務化了,下面的代碼片斷會有點凌亂。redis
// 調用獲取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,祕鑰>的<key,value>形式存儲到redis,設置其有效時間爲5秒5秒看本身狀況不要太大也不要過短,設置有效期是爲了防止被其餘人截取到加密密碼冒充用戶的狀況,把風險降更低
。segmentfault
// 判斷若爲獲取登陸註冊加密動態祕鑰請求 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); }
持續更新。。。。。。
分享一波阿里雲代金券快速上雲
app
轉載請註明 from tomsun28前後端分離