前端
在main.js中导入了import '@/permission'
在permission.js中设置了路由全局守卫,见下图代码所示:

上述代码中Vue.ls.get(ACCESS_TOKEN)是判断浏览器localStorage中是否有ACCESS_TOKEN,如果有,则表明已经登录了。
否则需要路由到next({ path: '/user/login', query: { redirect: to.fullPath } })
假如我们还未登录,查看路由表(在router.config.js中),如下图所示:

发现/user/login可知对应的登录界面是@/views/user/Login.vue
顺势在@/views/user/Login.vue中找到登录按钮

绑定的方法是handleSubmit

在handleSubmit中真正触发登录请求的地方是上图中红色框中的代码。
that.Login实际是this.Login,Login方法是通过vuex组件分发action技术引入的

关于项目中如何使用vuex请配合vuex官方文档仔细阅读下图所示部分代码

我们刚刚提到的Login方法真正定义的地方是在user.js中,代码位置如下图所示:

上图标记1实际上是发起了一个axios请求(即请求后端登录接口/sys/login),代码如下:
export function login(parameter) {return axios({url: '/sys/login',method: 'post',data: parameter})}
标记2是后端登录成功后前端设置一些localStorage、并且更新vuex state,比较关键的是Vue.ls.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
后端
后端对应的登录接口位置如图:

分段解析下:
String username = sysLoginModel.getUsername();
String password = sysLoginModel.getPassword();
//update-begin--Author:scott Date:20190805 for:暂时注释掉密码加密逻辑,有点问题
//前端密码加密,后端进行密码解密
//password = AesEncryptUtil.desEncrypt(sysLoginModel.getPassword().replaceAll("%2B", "\\+")).trim();//密码解密
//update-begin--Author:scott Date:20190805 for:暂时注释掉密码加密逻辑,有点问题
//update-begin-author:taoyan date:20190828 for:校验验证码
String captcha = sysLoginModel.getCaptcha();
if(captcha==null){
result.error500("验证码无效");
return result;
}
String lowerCaseCaptcha = captcha.toLowerCase();
String realKey = MD5Util.MD5Encode(lowerCaseCaptcha+sysLoginModel.getCheckKey(), "utf-8");
Object checkCode = redisUtil.get(realKey);
if(checkCode==null || !checkCode.equals(lowerCaseCaptcha)) {
result.error500("验证码错误");
return result;
}
这一段主要是拿前端传过来的验证码和redis中的验证码进行比较
//1. 校验用户是否有效
SysUser sysUser = sysUserService.getUserByName(username);
result = sysUserService.checkUserIsEffective(sysUser);
if(!result.isSuccess()) {
return result;
}
//2. 校验用户名或密码是否正确
String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
String syspassword = sysUser.getPassword();
if (!syspassword.equals(userpassword)) {
result.error500("用户名或密码错误");
return result;
}
检查用户名是否有效以及密码是否正确
//将用户信息放进result中
userInfo(sysUser, result);
sysBaseAPI.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null);
return result;
主要就是userInfo(sysUser, result);,作用是将用户信息放进result中。
我们不用看userInfo(sysUser, result)的内部实现,直接看result的数据结构(数据样例)如何:

其他
登录完成之后,后续对服务器的请求都会从Vue.ls.get(ACCESS_TOKEN)取出ACCESS_TOKEN,放入到http头部X-Access-Token中。
例如 请求个人中心页面http://localhost:3000/account/center :


注意上图请求头中有X-Access-Token
前端是怎么把X-Access-Token放进去的呢?我们来跟踪代码:
首先找到个人中心这个页面center/Index.vue

发现this.$http并没有设置头部X-Access-Token,那肯定在一个地方全局配置的。
经过一番搜索,发现是在utils/request.js中

在这里拦截每一个请求,给它们设置X-Access-Token头部
后端服务器配置了shiro过滤器,会拦截一些特定url,比如上面的/workplace/teams。



后端会从被拦截到的请求头中取出X_ACCESS_TOKEN,然后交给shiro realm 认证这个token.
首先token不能为空,然后在checkUserTokenIsEffect(token)中校验用户名、密码以及是否过期。
注意:后端token有效时间设置为EXPIRETIME = 30 60 _ 1000; 30分钟 和 前端7天是不一样的
