当前位置: 首页 > news >正文

网站建设 推广企业税率新闻大全

网站建设 推广企业税率,新闻大全,互联网网站建设门户网,dw网站首页的导航怎么做jeecg库(版本jeecg-boot-v3.5.1last)实现了用户登录功能,二开时为了借鉴jeecg用户登录的方法,跑了一遍登录方法: org.jeecg.modules.system.controller.LoginController#login 定义这个方法的类的路径是:…

jeecg库(版本jeecg-boot-v3.5.1last)实现了用户登录功能,二开时为了借鉴jeecg用户登录的方法,跑了一遍登录方法:

org.jeecg.modules.system.controller.LoginController#login

定义这个方法的类的路径是:

jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java

截图:

login方法代码:

	@ApiOperation("登录接口")@RequestMapping(value = "/login", method = RequestMethod.POST)public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel){Result<JSONObject> result = new Result<JSONObject>();String username = sysLoginModel.getUsername();String password = sysLoginModel.getPassword();//update-begin-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户if(isLoginFailOvertimes(username)){return result.error500("该用户登录失败次数过多,请于10分钟后再次登录!");}//update-end-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户//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();//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906// 加入密钥作为混淆,避免简单的拼接,被外部利用,用户自定义该密钥即可String origin = lowerCaseCaptcha+sysLoginModel.getCheckKey()+jeecgBaseConfig.getSignatureSecret();String realKey = Md5Util.md5Encode(origin, "utf-8");//update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906Object checkCode = redisUtil.get(realKey);//当进入登录页时,有一定几率出现验证码错误 #1714if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {log.warn("验证码错误,key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);result.error500("验证码错误");// 改成特殊的code 便于前端判断result.setCode(HttpStatus.PRECONDITION_FAILED.value());return result;}//update-end-author:taoyan date:20190828 for:校验验证码//1. 校验用户是否有效//update-begin-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug,if条件永远为falseLambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(SysUser::getUsername,username);SysUser sysUser = sysUserService.getOne(queryWrapper);//update-end-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug,if条件永远为falseresult = 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)) {//update-begin-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户addLoginFailOvertimes(username);//update-end-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户result.error500("用户名或密码错误");return result;}//用户登录信息userInfo(sysUser, result);//update-begin--Author:liusq  Date:20210126  for:登录成功,删除redis中的验证码redisUtil.del(realKey);//update-begin--Author:liusq  Date:20210126  for:登录成功,删除redis中的验证码redisUtil.del(CommonConstant.LOGIN_FAIL + username);LoginUser loginUser = new LoginUser();BeanUtils.copyProperties(sysUser, loginUser);baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);//update-end--Author:wangshuai  Date:20200714  for:登录日志没有记录人员return result;}

看起来非常多,但学过源码分析课就知道,大部分都是准备过程,关键代码不多。

(源码分析课我看的马士兵教育连鹏举老师的)马士兵全套Spring源码深度解析:AOP、IOC、Bean生命周期、循环依赖、事务、SpringBoot自动装配等_哔哩哔哩_bilibili

前三行功能是,创建返回结果空对象,取用户端传递的用户名和密码(原始密码,未加密):

        Result<JSONObject> result = new Result<JSONObject>();
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();

紧接着一个判断语句,看用户是否频繁登录,这里产生了一个支线任务,为了避免本文过于冗长,只走正常登录相关的主线,有精力再研究支线:

if(isLoginFailOvertimes(username)){return result.error500("该用户登录失败次数过多,请于10分钟后再次登录!");
}

接下来取图片验证码,captcha是Completely Automated Public Turing Test to Tell Computers and Humans Apart (全自动区分计算机和人类的图灵测试)的简称,判断来登录的是不是爬虫程序。包含一个if(captcha==null)支线。

String captcha = sysLoginModel.getCaptcha();
if(captcha==null){result.error500("验证码无效");return result;
}
String lowerCaseCaptcha = captcha.toLowerCase();

下面是判断用户填写验证码是否正确的过程,代码复杂是因为做了加密处理,然后从redis中取验证码的原始字符串,因为这段代码没有生成验证码的过程,我大胆猜测下,图片验证码是根据redis中的checkCode生成的。后面还有一个验证码错误的支线,有精力可以研究。

String origin =lowerCaseCaptcha+sysLoginModel.getCheckKey()+jeecgBaseConfig.getSignatureSecret();

String realKey = Md5Util.md5Encode(origin, "utf-8");

Object checkCode = redisUtil.get(realKey);

if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {

log.warn("验证码错误,key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);

result.error500("验证码错误"); // 改成特殊的code 便于前端判断 result.setCode(HttpStatus.PRECONDITION_FAILED.value());

return result; }

login方法代码前一半分析完了,很粗略但正合适,因为这部分只是登录的准备工作,以及一些支线任务,内容很简单,不是login方法的关键点。

下面是核心功能:1. 校验用户是否有效
使用了查询数据库,其中queryWrapper.eq(SysUser::getUsername,username)使用了lambda表达式写法,详见:
MybatisPlus:中QueryWrapper<>().lambda使用(条件查询)_.lambda().eq-CSDN博客
更多关于MybatisPlus的知识可以看:
黑马程序员最新MybatisPlus全套视频教程,4小时快速精通mybatis-plus框架_哔哩哔哩_bilibiliLambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysUser::getUsername,username);
SysUser sysUser = sysUserService.getOne(queryWrapper);result = sysUserService.checkUserIsEffective(sysUser);
if(!result.isSuccess()) {return result;
}

sysUserService.checkUserIsEffective(sysUser)是确认用户有效性的方法,可以瞟一眼。

org.jeecg.modules.system.service.impl.SysUserServiceImpl#checkUserIsEffective源码:

	@Overridepublic Result<?> checkUserIsEffective(SysUser sysUser) {Result<?> result = new Result<Object>();//情况1:根据用户信息查询,该用户不存在if (sysUser == null) {result.error500("该用户不存在,请注册");baseCommonService.addLog("用户登录失败,用户不存在!", CommonConstant.LOG_TYPE_1, null);return result;}//情况2:根据用户信息查询,该用户已注销//update-begin---author:王帅   Date:20200601  for:if条件永远为falsebug------------if (CommonConstant.DEL_FLAG_1.equals(sysUser.getDelFlag())) {//update-end---author:王帅   Date:20200601  for:if条件永远为falsebug------------baseCommonService.addLog("用户登录失败,用户名:" + sysUser.getUsername() + "已注销!", CommonConstant.LOG_TYPE_1, null);result.error500("该用户已注销");return result;}//情况3:根据用户信息查询,该用户已冻结if (CommonConstant.USER_FREEZE.equals(sysUser.getStatus())) {baseCommonService.addLog("用户登录失败,用户名:" + sysUser.getUsername() + "已冻结!", CommonConstant.LOG_TYPE_1, null);result.error500("该用户已冻结");return result;}return result;}

都是简单的逻辑判断,判断过程不需要数据库交互。

回到login方法,核心功能2. 校验用户名或密码是否正确,注意从数据库获取的密码是加密后的,前台提交的密码也需要使用相同的MD5加密方式加密,才能验证是否与数据库存储的密码相等。

String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
String syspassword = sysUser.getPassword();
if (!syspassword.equals(userpassword)) {//平台用户登录失败锁定用户addLoginFailOvertimes(username);//平台用户登录失败锁定用户result.error500("用户名或密码错误");return result;
}

最后一段执行登录过程,在前面验证都通过后,才完成登录认证过程,包括将登录用户的token存入redis,以便后续请求直接比对token,userInfo(sysUser, result);中执行的就是向redis存入token和其他用户信息的操作。

//用户登录信息
userInfo(sysUser, result);
//登录成功,删除redis中的验证码
redisUtil.del(realKey);
//登录成功,删除redis中的验证码
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
LoginUser loginUser = new LoginUser();
BeanUtils.copyProperties(sysUser, loginUser);
baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);//登录日志没有记录人员
return result;

userInfo(sysUser, result)引用包名:

org.jeecg.modules.system.controller.LoginController#userInfo

	private Result<JSONObject> userInfo(SysUser sysUser, Result<JSONObject> result) {String username = sysUser.getUsername();String syspassword = sysUser.getPassword();// 获取用户部门信息JSONObject obj = new JSONObject(new LinkedHashMap<>());//1.生成tokenString token = JwtUtil.sign(username, syspassword);// 设置token缓存有效时间redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);obj.put("token", token);//2.设置登录租户Result<JSONObject> loginTenantError = sysUserService.setLoginTenant(sysUser, obj, username,result);if (loginTenantError != null) {return loginTenantError;}//3.设置登录用户信息obj.put("userInfo", sysUser);//4.设置登录部门List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());obj.put("departs", departs);if (departs == null || departs.size() == 0) {obj.put("multi_depart", 0);} else if (departs.size() == 1) {sysUserService.updateUserDepart(username, departs.get(0).getOrgCode(),null);obj.put("multi_depart", 1);} else {//查询当前是否有登录部门// update-begin--Author:wangshuai Date:20200805 for:如果用戶为选择部门,数据库为存在上一次登录部门,则取一条存进去SysUser sysUserById = sysUserService.getById(sysUser.getId());if(oConvertUtils.isEmpty(sysUserById.getOrgCode())){sysUserService.updateUserDepart(username, departs.get(0).getOrgCode(),null);}// update-end--Author:wangshuai Date:20200805 for:如果用戶为选择部门,数据库为存在上一次登录部门,则取一条存进去obj.put("multi_depart", 2);}obj.put("sysAllDictItems", sysDictService.queryAllDictItems());result.setResult(obj);result.success("登录成功");return result;}

userInfo方法,通过用户名和密码(已MD5加密)生成token,并存入redis,同时设置有效期(Token有效期为24小时,Token在reids中缓存时间乘以2),正常登录流程到这里就结束了。

接下来的2.设置登录租户代码sysUserService.setLoginTenant(sysUser, obj, username,result);,小心假设是有关鉴权的,

後面的3.设置登录用户信息和4.设置登录部门,這兩部分實現用戶多部門切換功能的,跟登錄無關。把用戶當前登錄的部門記錄到sys_user表中。

org.jeecg.modules.system.service.impl.SysUserServiceImpl#setLoginTenant源码:

	@Overridepublic Result<JSONObject>  setLoginTenant(SysUser sysUser, JSONObject obj, String username, Result<JSONObject> result){// update-begin--Author:sunjianlei Date:20210802 for:获取用户租户信息//用户有哪些租户List<SysTenant> tenantList = null;//update-begin---author:wangshuai ---date:20221223  for:[QQYUN-3371]租户逻辑改造,改成关系表------------List<Integer> tenantIdList = relationMapper.getTenantIdsNoStatus(sysUser.getId());if (null!=tenantIdList && tenantIdList.size()>0) {//update-end---author:wangshuai ---date:20221223  for:[QQYUN-3371]租户逻辑改造,改成关系表--------------//-------------------------------------------------------------------------------------//查询有效的租户集合LambdaQueryWrapper<SysTenant> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.in(SysTenant::getId, tenantIdList);queryWrapper.eq(SysTenant::getStatus, Integer.valueOf(CommonConstant.STATUS_1));tenantList = sysTenantMapper.selectList(queryWrapper);//-------------------------------------------------------------------------------------if (tenantList.size() == 0) {return result.error500("与该用户关联的租户均已被冻结,无法登录!");} else {obj.put("tenantList", tenantList);}}// update-end--Author:sunjianlei Date:20210802 for:获取用户租户信息//登录会话租户ID,有效性重置if (tenantList != null && tenantList.size() > 0) {if (tenantList.size() == 1) {sysUser.setLoginTenantId(tenantList.get(0).getId());} else {List<SysTenant> listAfterFilter = tenantList.stream().filter(s -> s.getId().equals(sysUser.getLoginTenantId())).collect(Collectors.toList());if (listAfterFilter == null || listAfterFilter.size() == 0) {//如果上次登录租户ID,在用户拥有的租户集合里面没有了,则随机取用户拥有的第一个租户IDsysUser.setLoginTenantId(tenantList.get(0).getId());}}} else {//无租户的时候,设置为 0sysUser.setLoginTenantId(0);}//设置用户登录缓存租户this.updateUserDepart(username, null,sysUser.getLoginTenantId());log.info(" 登录接口用户的租户ID = {}", sysUser.getLoginTenantId());if(sysUser.getLoginTenantId()!=null){//登录的时候需要手工设置下会话中的租户ID,不然登录接口无法通过租户隔离查询到数据TenantContext.setTenant(sysUser.getLoginTenantId()+"");}return null;}

代码中的操作都是数据库操作,这里需要留个伏笔,鉴权信息存入数据库后,将来如何调取,前台如何按权限显示不同的信息,需要进一步查找shiro的配置。

至此登录逻辑已执行完毕,回到主程序中:

redisUtil.del(realKey);
//登录成功,删除redis中的验证码
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
LoginUser loginUser = new LoginUser();
BeanUtils.copyProperties(sysUser, loginUser);
baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);//登录日志没有记录人员
return result;

剩余的操作是,删除redis验证码等,注意new LoginUser()并不用于登录,仅仅为了记录日志时,对象类型统一,因为已经登录的用户是通过shiro的subject方法获得用户信息的,获取的用户对象正是LoginUser类型。接下来将sysUser中的信息复制到loginUser中,通过baseCommonService.addLog添加到日志中。

整个登录过程分析完毕。登录后,用户再次访问系统时,会进入shiro的认证和授权过程,这部分内容也很重要,留待后续分析。

理解OAuth 2.0 - 阮一峰的网络日志 (ruanyifeng.com)

http://www.yayakq.cn/news/876214/

相关文章:

  • 响应式网站开发设计如何将网站挂载域名
  • 做的网站怎么发布到网上源码网站建设
  • 优惠券网站要怎么做网站制作主题思路
  • 建一个自己的网站需要多少钱html标签属性
  • 怎么做外贸个人网站邢台哪儿专业做网站
  • 岳阳网站建设一站式服务WordPress用rds云数据库
  • 怎么在搜狐快站上做网站个人网页免费域名注册入口
  • 连连建设跨境电商网站怎么更改wordpress文件上传大小
  • 水墨画风格网站设计师一般是什么学历
  • 镇江网站排名优化公司网站界面设计中的版式设计有哪些
  • 网站建设答辩ppt要点建设街小学网站
  • 辽宁网站制作设计模板图
  • 怎么做虚拟的网站佛山专业网站建设
  • 石家庄模板自助建站wordpress用什么linux
  • 徐州网站设计价位中国企业资讯网
  • dota2海涛做的网站建设网站应该加什么服务
  • 可以直接进入的舆情网站做网站能改吗
  • 标准网站建设公司wordpress 插件 语言包
  • 茶叶网站实际案例关键词优化的内容
  • 秦皇岛做网站的公司哪家好网站建设入门基础
  • 大网站制作公司哈尔滨网站建设公司哪家好
  • 网站速度查询建站技术入门
  • 加拿大28网站开发网页制作培训上海
  • 专门帮人做网站的公司如何做公司网站运营
  • 安康市城乡建设规划局网站php网站后台开发
  • 网上商城建站工作室网站服务器安全部署
  • 网站建设动态静态如何来做网站
  • 深圳宝安区住房和建设局网站静态网页设计教程
  • 有哪些做调查问卷赚钱的网站外贸如何网络推广
  • 预付网站制作费怎么做凭证长沙seo优化推广