2.若依中的认证中心
1.前言
在本节中主要是介绍若依微服务版本中的认证功能以及流程实现,认证功能主要包含注册、登录认证,用户注销,刷新token等。
2.项目实现
2.1 导入依赖
在该依赖中包含nacos注册发现、配置、sentinel、web、Actuator、ruoyi-common-security等依赖包,其中ruoyi-common-security需要我们导入依赖并搭建项目作为ruoyi-auth模块的子模块

<dependencies> <!-- SpringCloud Alibaba Nacos --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- SpringCloud Alibaba Nacos Config --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!-- SpringCloud Alibaba Sentinel --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <!-- SpringBoot Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- SpringBoot Actuator --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- RuoYi Common Security--> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-common-security</artifactId> </dependency> </dependencies>
在ruoyi-common-security模块中包含webmvc、ruoyi-system、ruoyi-common-redis等依赖

<dependencies> <!-- Spring Web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <!-- RuoYi Api System --> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-api-system</artifactId> </dependency> <!-- RuoYi Common Redis--> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-common-redis</artifactId> </dependency> </dependencies>
在ruoyi-common-redis模块中包含redis、ruoyi-common-core等依赖

<dependencies> <!-- SpringBoot Boot Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- RuoYi Common Core--> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-common-core</artifactId> </dependency> </dependencies>
在ruoyi-common-core模块中包含OpenFeign、loadBalancer、SpringContextSupport、web、Transmittable ThreadLocal、PageHelper、Hibernate Validator、Jackson、FastJSON、Jwt、jaxb、lang、IO、excel、servlet、swagger等依赖。

<dependencies> <!-- SpringCloud Openfeign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- SpringCloud Loadbalancer --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> <!-- Spring Context Support --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <!-- Spring Web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> <!-- Transmittable ThreadLocal --> <dependency> <groupId>com.alibaba</groupId> <artifactId>transmittable-thread-local</artifactId> </dependency> <!-- Pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> </dependency> <!-- Hibernate Validator --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <!-- Jackson --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> <!-- Alibaba Fastjson --> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> </dependency> <!-- Jwt --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> </dependency> <!-- Jaxb --> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> </dependency> <!-- Apache Lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> <!-- Commons Io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> </dependency> <!-- excel工具 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> </dependency> <!-- Java Servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> </dependency> <!-- Swagger --> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-annotations</artifactId> </dependency> </dependencies>
2.2 编写bootstrap.yml文件
在该配置文件中包该模块的服务端口、应用名称、环境、nacos注册地址、配置中心地址、配置格式以及共享配置文件。

# Tomcat
server:
port: 9200
# Spring
spring:
application:
# 应用名称
name: ruoyi-auth
profiles:
# 环境配置
active: dev
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 127.0.0.1:8848
config:
# 配置中心地址
server-addr: 127.0.0.1:8848
# 配置文件格式
file-extension: yml
# 共享配置,即将application.dev.yml作为共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
2.3 form类(注册和登录实体类)
在用户登录和注册实体类中,注册实体类继承了登录实体类,他们都只有username和password字段以及对应get和set方法

package com.ruoyi.auth.form; /** * 用户登录对象 * * @author ruoyi */ public class LoginBody { /** * 用户名 */ private String username; /** * 用户密码 */ private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }

package com.ruoyi.auth.form; /** * 用户注册对象 * * @author ruoyi */ public class RegisterBody extends LoginBody { }
2.4 service包(用户登录逻辑类、登录密码逻辑类、记录日志类)
2.4.1 SysLoginService
该服务类是通过@Component注解注入到Spring容器中,该类包含用户注册、登录、注销流程。
注册流程主要是检验注册用户/密码是否填写、账户长度、密码长度等问题,接着设置用户信息,并通过远程调用RemoteUserService实现用户注册,并将注册信息记录同步到数据库中。
登录流程主要是检验用户/密码是否填写、用户名和密码是否在指定范围、IP是否在黑名单、登录用户是否存在,是否删除、禁用。然后根据用户信息和密码通过调用passwordService验证密码,最后通过SysRecordLogService实例同步登录日志记录到数据库。
注销流程通过SysRecordLogService实例同步注销日志记录到数据库

1 package com.ruoyi.auth.service; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Component; 5 import com.ruoyi.common.core.constant.CacheConstants; 6 import com.ruoyi.common.core.constant.Constants; 7 import com.ruoyi.common.core.constant.SecurityConstants; 8 import com.ruoyi.common.core.constant.UserConstants; 9 import com.ruoyi.common.core.domain.R; 10 import com.ruoyi.common.core.enums.UserStatus; 11 import com.ruoyi.common.core.exception.ServiceException; 12 import com.ruoyi.common.core.text.Convert; 13 import com.ruoyi.common.core.utils.StringUtils; 14 import com.ruoyi.common.core.utils.ip.IpUtils; 15 import com.ruoyi.common.redis.service.RedisService; 16 import com.ruoyi.common.security.utils.SecurityUtils; 17 import com.ruoyi.system.api.RemoteUserService; 18 import com.ruoyi.system.api.domain.SysUser; 19 import com.ruoyi.system.api.model.LoginUser; 20 21 /** 22 * 登录校验方法 23 * 24 * @author ruoyi 25 */ 26 @Component 27 public class SysLoginService 28 { 29 @Autowired 30 private RemoteUserService remoteUserService; 31 32 @Autowired 33 private SysPasswordService passwordService; 34 35 @Autowired 36 private SysRecordLogService recordLogService; 37 38 @Autowired 39 private RedisService redisService; 40 41 /** 42 * 登录 43 */ 44 public LoginUser login(String username, String password) 45 { 46 // 用户名或密码为空 错误 47 if (StringUtils.isAnyBlank(username, password)) 48 { 49 recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写"); 50 throw new ServiceException("用户/密码必须填写"); 51 } 52 // 密码如果不在指定范围内 错误 53 if (password.length() < UserConstants.PASSWORD_MIN_LENGTH 54 || password.length() > UserConstants.PASSWORD_MAX_LENGTH) 55 { 56 recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户密码不在指定范围"); 57 throw new ServiceException("用户密码不在指定范围"); 58 } 59 // 用户名不在指定范围内 错误 60 if (username.length() < UserConstants.USERNAME_MIN_LENGTH 61 || username.length() > UserConstants.USERNAME_MAX_LENGTH) 62 { 63 recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围"); 64 throw new ServiceException("用户名不在指定范围"); 65 } 66 // IP黑名单校验 67 String blackStr = Convert.toStr(redisService.getCacheObject(CacheConstants.SYS_LOGIN_BLACKIPLIST)); 68 if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) 69 { 70 recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "很遗憾,访问IP已被列入系统黑名单"); 71 throw new ServiceException("很遗憾,访问IP已被列入系统黑名单"); 72 } 73 // 查询用户信息 74 R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER); 75 76 if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) 77 { 78 recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在"); 79 throw new ServiceException("登录用户:" + username + " 不存在"); 80 } 81 82 if (R.FAIL == userResult.getCode()) 83 { 84 throw new ServiceException(userResult.getMsg()); 85 } 86 87 LoginUser userInfo = userResult.getData(); 88 SysUser user = userResult.getData().getSysUser(); 89 if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) 90 { 91 recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除"); 92 throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); 93 } 94 if (UserStatus.DISABLE.getCode().equals(user.getStatus())) 95 { 96 recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员"); 97 throw new ServiceException("对不起,您的账号:" + username + " 已停用"); 98 } 99 passwordService.validate(user, password); 100 recordLogService.recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功"); 101 return userInfo; 102 } 103 104 public void logout(String loginName) 105 { 106 recordLogService.recordLogininfor(loginName, Constants.LOGOUT, "退出成功"); 107 } 108 109 /** 110 * 注册 111 */ 112 public void register(String username, String password) 113 { 114 // 用户名或密码为空 错误 115 if (StringUtils.isAnyBlank(username, password)) 116 { 117 throw new ServiceException("用户/密码必须填写"); 118 } 119 if (username.length() < UserConstants.USERNAME_MIN_LENGTH 120 || username.length() > UserConstants.USERNAME_MAX_LENGTH) 121 { 122 throw new ServiceException("账户长度必须在2到20个字符之间"); 123 } 124 if (password.length() < UserConstants.PASSWORD_MIN_LENGTH 125 || password.length() > UserConstants.PASSWORD_MAX_LENGTH) 126 { 127 throw new ServiceException("密码长度必须在5到20个字符之间"); 128 } 129 130 // 注册用户信息 131 SysUser sysUser = new SysUser(); 132 sysUser.setUserName(username); 133 sysUser.setNickName(username); 134 sysUser.setPassword(SecurityUtils.encryptPassword(password)); 135 R<?> registerResult = remoteUserService.registerUserInfo(sysUser, SecurityConstants.INNER); 136 137 if (R.FAIL == registerResult.getCode()) 138 { 139 throw new ServiceException(registerResult.getMsg()); 140 } 141 recordLogService.recordLogininfor(username, Constants.REGISTER, "注册成功"); 142 } 143 }
2.4.2 SysPasswordService
2.4.3 SysRecordLogService
项目链接
RuoYi-Cloud: 🎉 基于Spring Boot、Spring Cloud & Alibaba的分布式微服务架构权限管理系统,同时提供了 Vue3 的版本 (gitee.com)