feat: 实现完整的 RBAC 权限管理系统与基础设施增强

在初始认证基础上,新增完整的 RBAC 权限模型(角色、权限、菜单三级管理),
  集成审计日志、接口限流、登录失败锁定、Refresh Token 机制、Redis 分布式缓存与锁、
  RocketMQ 消息队列,并引入 Flyway 数据库版本管理,同时补充项目文档与使用示例
This commit is contained in:
2026-04-10 10:58:22 +08:00
parent 3a9bf61839
commit 40c85c3c1f
97 changed files with 13434 additions and 351 deletions

View File

@@ -0,0 +1,94 @@
package com.aisi.template.domain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 登录响应视图对象
* 用于返回登录成功后的响应数据
*
* 主要字段:
* 1. Token 信息:访问令牌、刷新令牌、过期时间
* 2. 用户信息用户ID、用户名、邮箱
*
* 使用场景:
* - 用户登录成功后返回
* - 用户注册成功后返回(自动登录)
* - Token 刷新后返回
*
* @author Claude
* @since 2024-04-09
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "登录响应")
public class LoginResponseVo {
/**
* 访问令牌Access Token
* - 用于 API 访问认证
* - 放在请求头Authorization: Bearer {accessToken}
* - 默认有效期1 小时
*/
@Schema(description = "访问令牌")
private String accessToken;
/**
* 刷新令牌Refresh Token
* - 用于获取新的 Access Token
* - 当 Access Token 过期时使用
* - 默认有效期7 天
*/
@Schema(description = "刷新令牌")
private String refreshToken;
/**
* 访问令牌过期时间(秒)
* - 默认3600 秒1 小时)
* - 前端可根据此时间提前刷新 Token
*/
@Schema(description = "访问令牌过期时间(秒)")
private Long expiresIn;
/**
* 用户信息
* - 包含用户的基本信息
* - 前端可显示用户名等信息
*/
@Schema(description = "用户信息")
private UserInfoVo userInfo;
/**
* 用户信息视图对象
* 包含用户的基本信息
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "用户信息")
public static class UserInfoVo {
/**
* 用户ID
*/
@Schema(description = "用户ID")
private Long id;
/**
* 用户名
*/
@Schema(description = "用户名")
private String username;
/**
* 邮箱地址
*/
@Schema(description = "邮箱")
private String email;
}
}

View File

@@ -0,0 +1,228 @@
package com.aisi.template.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
import java.util.List;
/**
* 菜单视图对象
* 用于返回菜单信息给前端
*
* 主要字段:
* 1. 基本信息菜单ID、父菜单ID、菜单名称、菜单类型
* 2. 菜单配置:路径、组件、图标、排序
* 3. 显示控制:可见性、启用状态
* 4. 权限控制:权限编码
* 5. 子菜单:子菜单列表(树形结构)
* 6. 时间信息:创建时间、更新时间
*
* @author Claude
* @since 2024-04-09
*/
public class MenuVo {
/**
* 菜单ID
*/
private Long id;
/**
* 父菜单ID
* - 0 或 null根菜单
* - 其他值:子菜单
*/
private Long parentId;
/**
* 菜单名称
*/
private String menuName;
/**
* 菜单类型
* - 1目录DIRECTORY
* - 2菜单MENU
* - 3按钮BUTTON
*/
private Integer menuType;
/**
* 菜单路径
* - 用于前端路由
*/
private String menuPath;
/**
* 组件路径
* - 前端组件文件路径
*/
private String component;
/**
* 菜单图标
* - 图标名称
*/
private String icon;
/**
* 排序字段
* - 数值越小越靠前
*/
private Integer sortOrder;
/**
* 可见性
* - 1可见
* - 0不可见
*/
private Integer visible;
/**
* 菜单状态
* - 1启用
* - 0禁用
*/
private Integer status;
/**
* 权限编码
* - 用于控制菜单的访问权限
*/
private String permissionCode;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime createdAt;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime updatedAt;
/**
* 子菜单列表
* - 用于构建菜单树形结构
* - 递归结构
*/
private List<MenuVo> children;
public MenuVo() {
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public Integer getMenuType() {
return menuType;
}
public void setMenuType(Integer menuType) {
this.menuType = menuType;
}
public String getMenuPath() {
return menuPath;
}
public void setMenuPath(String menuPath) {
this.menuPath = menuPath;
}
public String getComponent() {
return component;
}
public void setComponent(String component) {
this.component = component;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public Integer getSortOrder() {
return sortOrder;
}
public void setSortOrder(Integer sortOrder) {
this.sortOrder = sortOrder;
}
public Integer getVisible() {
return visible;
}
public void setVisible(Integer visible) {
this.visible = visible;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getPermissionCode() {
return permissionCode;
}
public void setPermissionCode(String permissionCode) {
this.permissionCode = permissionCode;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
public List<MenuVo> getChildren() {
return children;
}
public void setChildren(List<MenuVo> children) {
this.children = children;
}
}

View File

@@ -0,0 +1,154 @@
package com.aisi.template.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
/**
* 权限视图对象
* 用于返回权限信息给前端
*
* 主要字段:
* 1. 基本信息权限ID、权限编码、权限名称
* 2. 资源操作:资源名称、操作类型
* 3. 描述和状态:描述信息、启用状态
* 4. 时间信息:创建时间、更新时间
*
* @author Claude
* @since 2024-04-09
*/
public class PermissionVo {
/**
* 权限ID
*/
private Long id;
/**
* 权限编码
* - 格式:资源:操作
* - 示例user:read, role:write
*/
private String permissionCode;
/**
* 权限名称
* - 用于界面展示
* - 示例:查看用户、编辑角色
*/
private String permissionName;
/**
* 资源名称
* - 示例user, role, menu
*/
private String resource;
/**
* 操作类型
* - read读取查看
* - write写入创建/编辑)
* - delete删除
*/
private String action;
/**
* 权限描述
*/
private String description;
/**
* 权限状态
* - 1启用
* - 0禁用
*/
private Integer status;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime createdAt;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime updatedAt;
public PermissionVo() {
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPermissionCode() {
return permissionCode;
}
public void setPermissionCode(String permissionCode) {
this.permissionCode = permissionCode;
}
public String getPermissionName() {
return permissionName;
}
public void setPermissionName(String permissionName) {
this.permissionName = permissionName;
}
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
}

View File

@@ -0,0 +1,152 @@
package com.aisi.template.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
import java.util.Set;
/**
* 角色视图对象
* 用于返回角色信息给前端
*
* 主要字段:
* 1. 基本信息角色ID、角色编码、角色名称、描述
* 2. 排序和状态:排序字段、启用状态
* 3. 权限信息:关联的权限列表
* 4. 时间信息:创建时间、更新时间
*
* @author Claude
* @since 2024-04-09
*/
public class RoleVo {
/**
* 角色ID
*/
private Long id;
/**
* 角色编码
* - 格式ROLE_ + 名称
* - 示例ROLE_USER, ROLE_ADMIN
*/
private String roleCode;
/**
* 角色名称
* - 用于界面展示
* - 示例:普通用户、管理员
*/
private String roleName;
/**
* 角色描述
*/
private String description;
/**
* 排序字段
* - 数值越小越靠前
*/
private Integer sortOrder;
/**
* 角色状态
* - 1启用
* - 0禁用
*/
private Integer status;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime createdAt;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime updatedAt;
/**
* 角色拥有的权限列表
*/
private Set<PermissionVo> permissions;
public RoleVo() {
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRoleCode() {
return roleCode;
}
public void setRoleCode(String roleCode) {
this.roleCode = roleCode;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getSortOrder() {
return sortOrder;
}
public void setSortOrder(Integer sortOrder) {
this.sortOrder = sortOrder;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
public Set<PermissionVo> getPermissions() {
return permissions;
}
public void setPermissions(Set<PermissionVo> permissions) {
this.permissions = permissions;
}
}

View File

@@ -5,30 +5,73 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.Set;
/**
* 用户视图对象
* 用于返回用户信息给前端
*
* 主要字段:
* 1. 基本信息用户ID、用户名、邮箱
* 2. 状态信息:启用/禁用状态
* 3. 角色信息:角色编码列表
* 4. 时间信息:创建时间、更新时间
*
* 注意:
* - 不包含密码等敏感信息
* - 角色只返回角色编码,不返回完整角色对象
*
* @author Claude
* @since 2024-04-09
*/
@Data
@Schema(description = "用户视图对象")
public class UserVo {
/**
* 用户ID
*/
@Schema(description = "用户ID")
private Long id;
/**
* 用户名
*/
@Schema(description = "用户名")
private String username;
/**
* 邮箱地址
*/
@Schema(description = "邮箱")
private String email;
/**
* 用户状态
* - 1正常启用
* - 0禁用
*/
@Schema(description = "状态1=正常 0=禁用)")
private Integer status;
@Schema(description = "角色USER=普通用户ADMIN=管理员)")
private String role;
/**
* 角色编码列表
* - 示例:["ROLE_USER", "ROLE_ADMIN"]
* - 只返回角色编码,不返回完整角色对象
*/
@Schema(description = "角色列表")
private Set<String> roles;
/**
* 创建时间
*/
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime createdAt;
/**
* 更新时间
*/
@Schema(description = "更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime updatedAt;