UNPKG

create-base-teek-theme

Version:

``` npm create base-teek-theme@latest my-first-blog ```

724 lines (592 loc) 26.1 kB
--- date: 2025-04-26 03:01:09 title: 认证模块 permalink: /pages/24f3f7 author: name: 华总 link: https://xiaoying.org.cn categories: - 后端 - 功能扩展 --- # Spring Boot 3 认证模块 ## 简介 `liyao-spring-boot3-starter-auth` 是一个基于 Spring Boot 3 的认证组件,提供了用户认证、权限校验等功能,可以快速集成到 Spring Boot 3 项目中,简化认证和授权的开发工作。 ## 功能特性 - 用户登录认证 - 基于注解的权限校验 - 可配置的路径过滤 - 支持用户角色管理 - 与 Spring Boot 3 无缝集成 ## 安装方法 ::: tip 依赖可能非最新版本,请前往[maven](https://central.sonatype.com/artifact/io.github.liyao52033/liyao-spring-boot3-starter-auth)获取最新版本 ::: 1、在项目的 `pom.xml` 文件中添加以下依赖 ```xml <dependency> <groupId>io.github.liyao52033</groupId> <artifactId>liyao-spring-boot3-starter-auth</artifactId> <version>1.2.0</version> </dependency> ``` 2、创建数据库表 ```sql SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id', `userAccount` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '账号', `userPassword` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '1442de8d3dfff7f35f2a5f7c108b02b6' COMMENT '密码', `userRole` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'user' COMMENT '用户角色:user/admin/ban', `accessKey` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户密钥', `secretKey` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '服务密钥', `userAvatar` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'https://aurora-1258839075.cos.ap-shanghai.myqcloud.com/user_avatar/1680499436154834947/sHPQruWl-1696599833532.jpg' COMMENT '用户头像', `userProfile` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '一个人的价值,不在于他拥有什么,而在于他能够为别人做些什么。”这句话强调了帮助和服务他人的重要性,不断地为他人奉献可以增加你的人生价值。' COMMENT '用户简介', `unionId` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '微信开放平台id', `mpOpenId` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '公众号openId', `userName` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户昵称', `createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `isDelete` tinyint NOT NULL DEFAULT 0 COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE, INDEX `idx_unionId`(`unionId` ASC) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1896739267784413188 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户' ROW_FORMAT = DYNAMIC; SET FOREIGN_KEY_CHECKS = 1; ``` ## 配置说明`application.yml` 中添加以下配置: ```yaml spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/demo username: xxxx password: xxxxx mybatis-plus: configuration: map-underscore-to-camel-case: false log-impl: org.apache.ibatis.logging.stdout.StdOutImpl mapper-locations: classpath*:mapper/*.xml global-config: db-config: logic-delete-field: isDelete # 全局逻辑删除的实体字段名 logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) liyao: auth: # 是否启用认证模块,默认为 true enabled: true # 允许直接访问的路径列表,不需要登录验证 allowed-paths: - /api/public/** - /api/health/** ``` ## 使用示例 ### 1. 用户登录认证 认证模块会自动拦截需要认证的请求,默认情况下,除了配置的 `allowed-paths` 和内置的一些路径(如 Swagger、登录注册接口等)外,其他接口都需要登录后才能访问。 ### 2. 基于注解的权限校验 使用 `@AuthCheck` 注解可以对方法进行权限校验: ```java import com.liyao.auth.annotation.AuthCheck; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { // 需要管理员角色才能访问 @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) @GetMapping("/api/admin/users") public Result listUsers() { // 业务逻辑 return Result.success(); } // 需要普通用户角色才能访问 @AuthCheck(mustRole = "user") @GetMapping("/api/user/info") public Result getUserInfo() { // 业务逻辑 return Result.success(); } } ``` ### 3. 获取当前登录用户 在 Service 或 Controller 中注入 `SysUserService`,然后使用 `getLoginUser` 方法获取当前登录用户: ```java import com.liyao.auth.model.entity.User; import com.liyao.auth.service.SysUserService; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @Resource private SysUserService sysUserService; @Operation(summary = "获取当前登录用户") @PostMapping("/current") public BaseResponse<User> getLoginUser(HttpServletRequest request) { User loginUser = sysUserService.getLoginUser(request); return ResultUtils.success(loginUser); } } ``` ### 4. 继承实体类并添加新字段 可以通过继承实体类来扩展用户信息,以下示例展示了如何创建新的实体类并添加额外字段: ```java import com.liyao.auth.model.entity.User; import lombok.Data; import lombok.EqualsAndHashCode; // 继承User类并添加新字段 @Data @EqualsAndHashCode(callSuper = true) public class ExtendedUser extends User { // 新增手机号字段 private String phone; // 新增地址字段 private String address; } ``` 在使用时,可以通过`SysUserService``getLoginUser`方法获取扩展后的用户信息: ```java @RestController public class UserController { @Resource private SysUserService sysUserService; @GetMapping("/extended") public BaseResponse<ExtendedUser> getExtendedUser(HttpServletRequest request) { ExtendedUser extendedUser =(ExtendedUser)sysUserService.getLoginUser(request); // 业务逻辑 return ResultUtils.success(extendedUser); } } ``` ### 5. 继承SysUserService扩展功能 可以通过继承`SysUserService`类来扩展服务功能,以下示例展示了如何添加自定义方法: ```java import com.liyao.auth.service.SysUserService; import com.liyao.auth.model.entity.User; import jakarta.servlet.http.HttpServletRequest; public class CustomUserService extends SysUserService { /** * 自定义方法:根据用户ID获取用户详细信息 * @param userId 用户ID * @return 用户详细信息 */ public UserDetailVO getUserDetail(long userId) { // 自定义业务逻辑 return new UserDetailVO(); } /** * 重写获取登录用户方法 * @param request HTTP请求 * @return 登录用户信息 */ @Override public User getLoginUser(HttpServletRequest request) { // 自定义获取登录用户逻辑 return super.getLoginUser(request); } } ``` ### 6. 自定义认证逻辑 如果需要自定义认证逻辑,可以通过实现自己的 `LoginFilter` 并注册为 Bean 来覆盖默认实现: ```java import com.liyao.auth.LoginProperties; import com.liyao.auth.aop.LoginFilter; import com.liyao.auth.model.entity.User; import jakarta.servlet.http.HttpServletRequest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @Configuration public class CustomAuthConfig { @Bean @Primary public LoginFilter customLoginFilter(LoginProperties loginProperties) { return new CustomLoginFilter(loginProperties); } } // 自定义登录过滤器实现 public class CustomLoginFilter implements LoginFilter { private final LoginProperties loginProperties; public CustomLoginFilter(LoginProperties loginProperties) { this.loginProperties = loginProperties; } @Override public User getLoginUser(HttpServletRequest request) { // 自定义获取登录用户的逻辑 // 例如:从请求头中获取token,然后从缓存或数据库中获取用户信息 String token = request.getHeader("Authorization"); if (token == null || token.isEmpty()) { return null; } // 这里实现自己的token验证和用户获取逻辑 // ... return null; // 返回获取到的用户或null } } ``` ## 用户角色 认证模块内置了以下用户角色: - `user`:普通用户 - `admin`:管理员 - `ban`:被封号用户 可以通过 `UserRoleEnum` 枚举类获取这些角色: ```java import com.liyao.auth.enums.UserRoleEnum; // 获取用户角色 String userRole = UserRoleEnum.USER.getValue(); // "user" String adminRole = UserRoleEnum.ADMIN.getValue(); // "admin" ``` ## SysUserService 服务方法 `SysUserService` 是认证模块的核心服务接口,提供了用户认证、权限管理等功能。以下是该接口提供的所有方法 ### 用户注册 ```java @RestController @RequestMapping("/user") public class UserController { @Resource private SysUserService sysUserService; /** * 用户注册接口 * 该接口用于处理用户注册请求,接收用户提交的账户信息,并将新用户的ID返回给前端 * 主要功能包括验证用户输入的信息(如账户名、密码等),并调用业务逻辑进行注册操作 * * @param request 用户注册请求体,包含用户账户、密码等信息 * @return 返回一个包含新用户ID的BaseResponse对象,用于前端后续操作 */ @Operation(summary = "用户注册") @PostMapping("/register") public BaseResponse<Long> userRegister(@RequestBody UserRegisterRequest request) { // 调用业务逻辑处理用户注册,传入用户账户、密码等信息 long userId = sysUserService.userRegister(request.getUserAccount(), request.getUserPassword(), request.getCheckPassword()); // 返回注册成功后的用户ID return ResultUtils.success(userId); } } ``` ### 用户登录 ```java @RestController @RequestMapping("/user") public class UserController { @Resource private SysUserService sysUserService; /** * 用户登录接口 * 该方法允许用户通过POST请求提交登录信息,包括用户名和密码,以实现用户身份验证 * * @param request 包含用户账户和密码的登录请求对象 * @param httpServletRequest HTTP请求对象,用于获取请求相关信息 * @return 返回一个包含登录用户信息的响应对象,若登录成功 */ @Operation(summary = "用户登录") @PostMapping("/login") public BaseResponse<LoginUserVO> userLogin(@RequestBody UserLoginRequest request, HttpServletRequest httpServletRequest) { // 调用业务服务层进行用户登录验证 LoginUserVO loginUserVO = sysUserService.userLogin(request.getUserAccount(), request.getUserPassword(), httpServletRequest); // 返回登录成功后的用户信息 return ResultUtils.success(loginUserVO); } } ``` ### 用户登出 ```java @RestController @RequestMapping("/user") public class UserController { @Resource private SysUserService sysUserService; /** * 用户登出接口 * 该方法处理用户的登出请求,通过HTTP POST方式接收请求 * 主要作用是调用sysUserService的userLogout方法来执行登出操作,并返回操作结果 * * @param request HttpServletRequest对象,包含请求信息,用于用户登出操作 * @return BaseResponse<Boolean> 返回一个布尔值,表示用户是否成功登出 */ @Operation(summary = "用户登出") @PostMapping("/logout") public BaseResponse<Boolean> userLogout(HttpServletRequest request) { boolean result = sysUserService.userLogout(request); return ResultUtils.success(result); } } ``` ### 获取当前登录用户 ```java /** * 获取当前登录用户信息 * 此方法通过Post请求获取当前登录用户的详细信息它接受HttpServletRequest对象作为参数, * 以便从请求中提取用户信息然后调用sysUserService的getLoginUser方法来获取User对象, * 最后使用ResultUtils.success方法封装User对象并返回 * * @param request HTTP请求对象,用于获取当前请求的信息 * @return 返回一个BaseResponse对象,其中包含执行结果和用户信息 */ @Operation(summary = "获取当前登录用户") @PostMapping("/current") public BaseResponse<User> getLoginUser(HttpServletRequest request) { User loginUser = sysUserService.getLoginUser(request); return ResultUtils.success(loginUser); } ``` ### 获取用户信息 #### 根据id获取脱敏的用户信息 ```java /** * 根据用户ID获取用户视图对象 * 该方法通过用户ID调用服务层获取用户数据,并将其封装为用户视图对象返回 * 主要用于前端获取用户详细信息展示 * * @param id 用户ID,用于指定需要获取的用户 * @param request HTTP请求对象,可用于获取请求相关的信息 * @return 返回一个包含用户视图对象的响应,表示获取成功的用户信息 */ @Operation(summary = "根据id获取包装类") @GetMapping("/get/vo") public BaseResponse<UserVO> getUserVOById(long id, HttpServletRequest request) { // 根据用户ID获取用户实体对象的响应 BaseResponse<User> response = getUserById(id, request); // 从响应中提取用户实体对象 User user = response.getData(); // 将用户实体对象封装为用户视图对象,并返回成功响应 return ResultUtils.success(sysUserService.getUserVO(user)); } ``` #### 根据id获取用户信息 ```java /** * 根据用户ID获取用户信息,此接口仅限管理员使用 * * @param id 用户ID,必须为正整数 * @param request HTTP请求对象,用于获取请求信息 * @return 返回封装了用户信息的BaseResponse对象 * @throws BusinessException 当用户ID不合法时抛出业务异常 */ @Operation(summary = "根据id获取用户(仅管理员)") @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) @GetMapping("/get") public BaseResponse<User> getUserById(long id, HttpServletRequest request) { // 检查用户ID是否为正整数,如果不是,抛出参数错误异常 if (id <= 0) { throw new BusinessException(ErrorCode.PARAMS_ERROR); } // 调用服务层方法,根据ID获取用户对象 User user = sysUserService.getById(id); // 如果用户不存在,抛出未找到错误异常 ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR); // 返回成功响应,包含用户信息 return ResultUtils.success(user); } ``` ### 获取分页的用户信息 ```java /** * 获取分页的用户信息 * 该接口用于处理用户信息的分页查询请求它接收一个包含分页参数和查询条件的请求体, * 根据这些条件查询用户信息,并返回一个分页的用户信息列表 * * @param userQueryRequest 包含用户查询条件和分页信息的请求体 * @param request HTTP请求对象,用于获取请求相关的信息 * @return 返回一个包含分页用户信息的响应对象 */ @Operation(summary = "获取分页的用户信息") @PostMapping("/vo/page") public BaseResponse<Page<UserVO>> getUserVOPage(@RequestBody UserQueryRequest userQueryRequest, HttpServletRequest request) { // 获取当前页码和页面大小 long current = userQueryRequest.getCurrent(); long size = userQueryRequest.getPageSize(); // 限制爬虫 if(size > 20){ throw new BusinessException(ErrorCode.PARAMS_ERROR); } // 使用SysUserService的page方法进行分页查询 Page<User> userPage = sysUserService.page(new Page<>(current, size), sysUserService.getQueryWrapper(userQueryRequest)); // 转换查询结果为UserVO类型的分页对象 Page<UserVO> userVOPage = sysUserService.getUserVOPage(userPage, request); // 返回成功响应,包含分页的用户信息 return ResultUtils.success(userVOPage); } ``` ### 密码管理 #### 用户自行修改密码 ```java /** * 修改用户密码接口 * 该接口允许用户更新自己的密码,采用POST请求方式 * * @param userUpdatePassword 包含用户ID和新密码的请求体对象 * @return 返回一个包含受影响用户ID的BaseResponse对象 */ @Operation(summary = "修改用户密码") @PostMapping("/update-password") public BaseResponse<Long> updateUserPassword(@RequestBody UserUpdatePassword userUpdatePassword) { // 调用服务层方法更新用户密码 long result = sysUserService.updateUserPassword(userUpdatePassword); // 返回成功结果,包含受影响的用户ID return ResultUtils.success(result); } ``` #### 管理员根据ID批量重置密码 ```java /** * 批量重置密码 * @param userResetPassword 用户重置密码对象 * @param request 请求 * @return 用户id */ @Operation(summary = "批量重置密码") @PostMapping("/reset/password") public BaseResponse<Long> resetPassword(@RequestBody UserResetPassword userResetPassword, HttpServletRequest request) { // 获取当前登录的用户 User loginUser = sysUserService.getLoginUser(request); // 获取当前登录用户的ID long id = loginUser.getId(); // 获取需要重置密码的用户ID列表 List<Long> ids = userResetPassword.getId(); // 获取这些用户的角色列表 List<String> squaredList = ids.stream().map(x -> sysUserService.getById(x).getUserRole()).toList(); // 定义目标角色为"admin" String target = "admin"; // 初始化标志变量以检查是否存在目标角色 boolean containsTarget = false; // 遍历角色列表检查是否存在目标角色 for (String num : squaredList) { if (Objects.equals(num, target)) { containsTarget = true; break; } } // 如果存在目标角色,则抛出异常,不允许重置密码 if (containsTarget) { ThrowUtils.throwIf(ErrorCode.NO_AUTH_ERROR, "仅可更新非管理员账号"); } // 定义新的密码值(保存到数据库中的密码值可填写到此) String value = "xxxx"; // 批量更新用户密码 sysUserService.updateBatchValue(ids, value); // 返回成功响应,包含当前登录用户的ID return ResultUtils.success(id); } ``` ### 权限管理 #### 通过HTTP GET请求来判断当前用户是否具有管理员权限 ```java /** * 检查用户是否为管理员 * 此方法通过HTTP GET请求来判断当前用户是否具有管理员权限 * 它首先调用sysUserService的isAdmin方法来获取用户是否为管理员的信息, * 然后使用ResultUtils.success方法封装结果并返回 * * @param request HttpServletRequest对象,包含请求相关的信息 * @return BaseResponse<Boolean> 返回一个布尔值,表示用户是否为管理员 */ @Operation(summary = "检查用户是否为管理员") @GetMapping("/is-admin") public BaseResponse<Boolean> isAdmin(HttpServletRequest request) { boolean isAdmin = sysUserService.isAdmin(request); return ResultUtils.success(isAdmin); } ``` #### 检查指定用户是否为管理员 ```java /** * 检查指定用户是否为管理员 * * @param userId 用户ID,用于标识待检查的用户 * @return BaseResponse<Boolean> 返回一个布尔值,指示用户是否为管理员 */ @Operation(summary = "检查指定用户是否为管理员") @GetMapping("/is-admin-by-user") public BaseResponse<Boolean> isAdminByUser(@RequestParam("userId") Long userId) { // 根据用户ID获取用户对象 User user = sysUserService.getById(userId); // 判断用户是否为管理员 boolean isAdmin = sysUserService.isAdmin(user); // 返回判断结果 return ResultUtils.success(isAdmin); } ``` ### 更新用户信息 ```java /** * 更新用户信息的接口方法 * 该方法通过POST请求接收用户更新请求,验证请求参数的有效性, * 然后将更新请求中的数据映射到用户实体,并调用服务层方法更新数据库中的用户信息 * * @param userUpdateRequest 包含用户更新信息的请求对象,不能为空且必须包含用户ID * @param request HTTP请求对象,用于可能需要的上下文信息 * @return 返回一个包含更新结果的BaseResponse对象,表示更新操作是否成功 * @throws BusinessException 如果请求参数无效(如为空或缺少ID),抛出业务异常 * @throws RuntimeException 如果更新操作失败,抛出运行时异常 */ @Operation(summary = "更新用户") @PostMapping("/update") public BaseResponse<Boolean> updateUser(@RequestBody UserUpdateRequest userUpdateRequest, HttpServletRequest request) { // 检查请求参数是否有效,如果无效则抛出业务异常 if (userUpdateRequest == null || userUpdateRequest.getId() == null) { throw new BusinessException(ErrorCode.PARAMS_ERROR); } // 创建一个新的User对象,并将请求参数中的属性复制到该对象 User user = new User(); BeanUtils.copyProperties(userUpdateRequest, user); // 调用服务层方法更新用户信息,并检查更新操作是否成功 boolean result = sysUserService.updateById(user); // 如果更新操作失败,抛出异常 ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR); // 返回更新操作成功的响应 return ResultUtils.success(true); } ``` ### 删除用户 #### 删除单个用户 ```java /** * 删除用户 * * @param id 用户id * @return 返回值类型为 BaseResponseBoolean 的描述 */ @Operation(summary = "删除用户") @DeleteMapping("/delete") public BaseResponse<Boolean> deleteUser(@RequestParam("id") long id) { if (id <= 0 || ObjectUtils.isEmpty(id)) { throw new BusinessException(ErrorCode.PARAMS_ERROR); } boolean b = sysUserService.removeById(id); return ResultUtils.success(b); } ``` #### 批量删除用户 ```java /** * 批量删除用户信息 * * @param ids 用户信息ID,多个以英文逗号(,)分割 * @return 删除结果,true表示删除成功,false表示删除失败 * @throws BusinessException 当参数无效时抛出的异常 */ @Operation(summary = "批量删除用户信息") @DeleteMapping("/{ids}") public BaseResponse<Boolean> deleteByIds(@Parameter(description = "用户信息ID,多个以英文逗号(,)分割") @PathVariable String ids) { // 检查传入的ID字符串是否为空或无效 if (StringUtils.isBlank(ids)) { throw new BusinessException(ErrorCode.PARAMS_ERROR); } // 调用服务层方法,传入ID字符串,执行批量删除操作 boolean result = sysUserService.deleteUsers(ids); // 返回删除结果 return ResultUtils.success(result); } } ``` ## 注意事项 1. 该认证模块依赖于 Spring Boot 3,不兼容 Spring Boot 2.x 版本。 2. 默认情况下,认证模块会自动扫描 `com.liyao.auth.mapper``com.liyao.auth.service``com.liyao.auth.aop``com.liyao.auth.model` 包下的组件。 3. 认证模块使用了 MyBatis-Plus,需要确保项目中已经配置了数据源。