应领导要求重构一套新的CRM系统,用户中心在原平台基础上进行开发。MVP版本发现以下两个bug:
1、使用验证码登录(此版本新功能)偶发页面无权限访问;
2、用户被删除之后还可以正常登录;
按照顺序排查bug:此项目会在用户登录成功后缓存用户信息及相关权限信息至redis中,用户登录成功但是接口层返回用户无权限(正常情况此用户具有访问权限);出现这种情况只能说明是redis中缓存的用户信息有误,查看后发现以下异常:
- 与正常用户对比缓存的用户信息中无permissions信息(直接导致页面访问异常);
- 缓存的账号信息与当前登录账号不一致!!!!
缓存的账号信息都不是想要登录的账号,有权限访问才怪了。定位代码发现问题所在:
SysUser user = sysUserDao.selectOne(new QueryWrapper<SysUser>()
.lambda()
.eq(SysUser::getUsername, username).or().eq(SysUser::getPhone,username)
.eq(SysUser::getDelFlag, Constants.DelFlag.NORMAL)
.last("limit 1"));
简单翻译一下这段执行的SQL语句:
SELECT
*
FROM
sys_user
WHERE
username = '18888888888'
OR phone = '18888888888'
AND del_flag = 'N'
LIMIT 1
这个查询语句会导致意外的结果:逻辑运算符的默认优先级将导致AND操作在OR操作之前执行。这意味着查询将匹配以下两种情况之一:
- username = '18888888888':只要用户名匹配,不管del_flag的值是什么,都会返回记录。
- phone = '18888888888' AND del_flag = 'N':只有在电话匹配且del_flag为'N'时才会返回记录。
看到这可以确定这两个bug都是因为这一行代码导致,如果出现了username与phone相同的被删除账号后,使用验证码登录就可能会匹配到被删除的账号信息:导致实际登录账号与想要登录的账号不一致
解决方法:
SysUser user = sysUserDao.selectOne(new QueryWrapper<SysUser>()
.lambda()
.and(QueryWrapper -> QueryWrapper.eq(SysUser::getUsername, username).or().eq(SysUser::getPhone,username))
.eq(SysUser::getDelFlag, Constants.DelFlag.NORMAL)
.last("limit 1"));