【前端必备技能java之若依框架认证(登录注册)模块梳理】

铁锅炖大鹅(e) 2024-06-16 12:33:03 阅读 79

详解若依框架微服务登录注册认证模块ruoyi-auth

认证模块目录结构为什么需要认证模块控制器(controller)业务实现(Service)登录业务注册业务

必备技能java系列梳理的文章并不涉及造轮子,以若依框架为基础,分析微服务Spring Cloud的能力,并理清微服务在业务处理上搭建的应用层架构,不会追问技术实践的底层细节,目标是可以让有后端经验的非java相关的程序员可以使用Spring Cloud搭建属于自己的后端服务

认证模块目录结构

请添加图片描述

上面的结构来自于若依认证模块仓库

src->main->java目录是SpringCloud项目在生成项目后的固定结构,com.ruoyi.auth为项目自定义,包含了若依认证模块的业务实现,

1、controller 为项目配置文件

2、form为登录注册使用的数据对象

3、service为网关的业务层实现resources目录下为本地配置,target为编译后的文件目录。

为什么需要认证模块

在这里插入图片描述

上面是若依的架构图,从上图可以看出当客户端发起Http请求之后,会首先进入网关,在网关这一层需要做认证处理,这里的认证包括生成Token,用户登录业务、用户注册业务、记录登录信息等。

实际上就是负责用户身份验证和授权,之所以会抽离为单独模块,是为了单独维护这一块的逻辑,方便后续的扩展比如集成第三方认证(OAuth验证),这种业务分割的方式也可以复用到其他类似的模块中。

控制器(controller)

Controller 负责处理用户的请求并调用后端代码(通常是服务层或业务逻辑层)来处理业务需求。看一下若依是如何在控制器中分发路由的。

@RestControllerpublic class TokenController{ @Autowired private TokenService tokenService; @Autowired private SysLoginService sysLoginService; // R<?> 标明需要返回的数据格式 @PostMapping("login") public R<?> login(@RequestBody LoginBody form) { // 用户登录 LoginUser userInfo = sysLoginService.login(form.getUsername(), form.getPassword()); // 获取登录token return R.ok(tokenService.createToken(userInfo)); } @DeleteMapping("logout") public R<?> logout(HttpServletRequest request) { String token = SecurityUtils.getToken(request); if (StringUtils.isNotEmpty(token)) { String username = JwtUtils.getUserName(token); // 删除用户缓存记录 AuthUtil.logoutByToken(token); // 记录用户退出日志 sysLoginService.logout(username); } return R.ok(); } @PostMapping("refresh") public R<?> refresh(HttpServletRequest request) { LoginUser loginUser = tokenService.getLoginUser(request); if (StringUtils.isNotNull(loginUser)) { // 刷新令牌有效期 tokenService.refreshToken(loginUser); return R.ok(); } return R.ok(); } @PostMapping("register") public R<?> register(@RequestBody RegisterBody registerBody) { // 用户注册 sysLoginService.register(registerBody.getUsername(), registerBody.getPassword()); return R.ok(); }}

@RestController 注解表示生成resfull风格的路由,同时也表明该类是一个 Spring 的 Controller,可以处理 HTTP 请求。

@Autowired 注解表示自动注入依赖,也就是以类型的方式识别Bean,在当前的控制器中可以调用依赖中的方法。

@PostMapping(“login”) 用来处理Post类型的请求,匹配到login请求后进入对应的方法中。

***@DeleteMapping(“logout”)***用于处理 DELETE 类型的请求,匹配到logout请求后进入对应的方法中。

业务实现(Service)

登录业务

控制器中的login方法调用业务层(service)的具体实现,包括用户名密码校验IP地址校验用户信息校验登录日志记录等:

流程图如下:

请添加图片描述

业务层实现:

public LoginUser login(String username, String password) { // 用户名或密码为空 错误 if (StringUtils.isAnyBlank(username, password)) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写"); throw new ServiceException("用户/密码必须填写"); } // 密码如果不在指定范围内 错误 if (password.length() < UserConstants.PASSWORD_MIN_LENGTH || password.length() > UserConstants.PASSWORD_MAX_LENGTH) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户密码不在指定范围"); throw new ServiceException("用户密码不在指定范围"); } // 用户名不在指定范围内 错误 if (username.length() < UserConstants.USERNAME_MIN_LENGTH || username.length() > UserConstants.USERNAME_MAX_LENGTH) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围"); throw new ServiceException("用户名不在指定范围"); } // IP黑名单校验 String blackStr = Convert.toStr(redisService.getCacheObject(CacheConstants.SYS_LOGIN_BLACKIPLIST)); if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "很遗憾,访问IP已被列入系统黑名单"); throw new ServiceException("很遗憾,访问IP已被列入系统黑名单"); } // 查询用户信息 R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER); if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在"); throw new ServiceException("登录用户:" + username + " 不存在"); } if (R.FAIL == userResult.getCode()) { throw new ServiceException(userResult.getMsg()); } LoginUser userInfo = userResult.getData(); SysUser user = userResult.getData().getSysUser(); if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除"); throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); } if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员"); throw new ServiceException("对不起,您的账号:" + username + " 已停用"); } passwordService.validate(user, password); recordLogService.recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功"); return userInfo; }

注册业务

控制器中的register方法调用业务层(service)的具体实现,包括用户名密码校验用户是否已注册等:

流程图如下:

请添加图片描述

业务层实现:

public void register(String username, String password) { // 用户名或密码为空 错误 if (StringUtils.isAnyBlank(username, password)) { throw new ServiceException("用户/密码必须填写"); } if (username.length() < UserConstants.USERNAME_MIN_LENGTH || username.length() > UserConstants.USERNAME_MAX_LENGTH) { throw new ServiceException("账户长度必须在2到20个字符之间"); } if (password.length() < UserConstants.PASSWORD_MIN_LENGTH || password.length() > UserConstants.PASSWORD_MAX_LENGTH) { throw new ServiceException("密码长度必须在5到20个字符之间"); } // 注册用户信息 SysUser sysUser = new SysUser(); sysUser.setUserName(username); sysUser.setNickName(username); sysUser.setPassword(SecurityUtils.encryptPassword(password)); R<?> registerResult = remoteUserService.registerUserInfo(sysUser, SecurityConstants.INNER); if (R.FAIL == registerResult.getCode()) { throw new ServiceException(registerResult.getMsg()); } recordLogService.recordLogininfor(username, Constants.REGISTER, "注册成功"); }

上述就是若依的登录注册流程,这中间还涉及到一些通用的工具类,可自行参考若依工具类代码。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。