这个模块分离至项目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前后端分离