Spring Security + vue3 前后端分离后台管理

vo: 返回数据给前端
dto: 从前端获取数据

项目极限更新中··········

如果多个修改或删除操作构成一个逻辑上的完整工作单元,它们必须保证原子性(即要么全部成功,要么全部失败)。在这种情况下,如果其中一个操作失败导致数据不一致,则整个事务应通过回滚恢复到事务开始前的状态。

Spring Security + vue3 前后端分离项目

  • api接口: https://apifox.com/apidoc/shared-2963bc24-5f7a-47e4-a099-97f93c632282
  • github仓库:https://github.com/1752597830/admin-common.git
    后端:

采用技术栈: Spring Security + SpringBoot + JWT + MybatisPlus + MybatisX + Redis

Spring Security前后端分离自定义登录

初始化项目

  • 创建项目
  • 配置maven
  • 编写工具类(BaseResponse响应类,封装了响应成功和失败。ResponseCode状态码枚举。ServletUtils 封装了响应流处理数据)
  • 抽取出有共同字段的属性 BaseEntity(创建时间、创建人、更新时间、更新人)
  • 配置MySQL
  • 使用MybatisX生成代码
  • 配置MybatisPlus

登录

  • 引入相关依赖
  • 配置跨域请求WebMvcConfig
  • 配置SpringSecurity
  • 配置自定义登录成功(LoginSuccessHandler)
  • 配置自定义登录失败(LoginFailureHandler)

封装JWT拦截器

  • 引入相关依赖
  • 在application.yml中配置token信息 方便管理
  • 封装JWT拦截器 JwtAuthenticationTokenFilter
  • 封装JWT工具类 JwtUtil 生成和解析token
  • 自定义JwtAuthentication用于解析token中获取到的用户信息 (Authentication及其实现类的大部分属性没有提供setter方法)
  • 添加拦截器到SpringSecurity配置类中,拦截器拦截到请求,判断是否登录,未登录则拦截,登录则放行(放在UsernamePasswordAuthenticationFilter前面)

验证码拦截器

  • 引入相关依赖
  • 封装验证码生成工具(放在通用工具类中)
  • 封装常量池存放验证码需要的数据(位数、长度、宽度)
  • 封装验证码拦截器 VerifyCodeFilter
  • 添加拦截器到SpringSecurity配置类中,拦截器拦截到请求,判断是否登录,未登录则拦截,登录则放行(放在UsernamePasswordAuthenticationFilter前面)

配置Redis

  • 引入相关依赖
  • 配置端口等信息
  • 自定义Redis配置类
  • 封装RedisCache

异常处理

  • BaseException 自定义异常类
  • globalException 全局异常处理类
  • NoAuthenticationEntryPoint Security异常处理类

用户接口

获取用户信息

  • 根据之前登录存放在Spring Security中的用户信息来获取
  • 封装SecurityUtils工具类来实现用户信息和权限的获取
  • 封装返回对象Vo

需要授权操作才能访问 自定义处理时需要实现权限校验

Spring Security权限

  • 通过拦截器方式动态封装权限校验 MyauthorizationManager
  • 在config配置中添加权限校验

新增用户

  • UserForm表单获取数据
  • 插入时使用事务进行处理(@Transactional),防止数据插入失败
  • 用自定义异常进行处理插入失败的状态

封装增删改异常或失败处理

  • ToolUtils中自定义处理方法isOk
  • 判断结构抛出异常,全局捕获处理

获取当前用户信息

  • 封装UserInfoVo(获取用户信息响应对象)
  • 解析Security中存储的数据 封装SecurityUtils获取登录时存储的用户信息

修改用户

  • UserForm表单获取数据
  • 修改时使用事务进行处理(@Transactional),防止数据修改失败
  • 判断结构抛出异常,全局捕获处理
public class UserForm {
    @Schema(description = "用户账号")
    private String username;

    @Schema(description = "用户昵称")
    private String nickname;

    @Schema(description = "用户邮箱")
    private String email;

    @Schema(description = "用户手机号")
    private String mobile;

    @Schema(description = "用户性别")
    private Integer gender;

    @Schema(description = "用户头像")
    private String avatar;

    @Schema(description="用户状态(0:正常;1:禁用)")
    private Integer status;

    @Schema(description = "角色ID集合")
    @NotEmpty(message = "用户角色不能为空")
    private List<Long> roleIds;
}

删除用户

  • 根据uid删除用户
  • 进行逻辑删除 修改字段is_deleted为1

分页用户

  • 封装分页对象 UserPageVo
  • BaseController中获取分页的pageSize和pageNum,封装PageHelp的startPage方法
  • 分页查询用户信息

重置用户密码

  • 根据用户id重置用户密码
  • 修改时使用事务进行处理(@Transactional),防止数据修改失败

根据uid获取用户信息

  • UserForm(获取用户信息响应对象,见上面UserForm)

修改密码

  • 封装修改密码对象
  • 修改密码时使用事务进行处理(@Transactional),防止数据修改失败
  • 修改密码时需要验证旧密码是否正确

上述修改操作后需要更新用户信息

菜单接口

获取路由

  • 封装路由对象RouteVo
  • 根据用户uid获取路由
  • 路由对象通过menu表,role表,role_menu表,user_role表,user表关联构建
public class RouteVo {
    /**
     * id
     */
    private Long id;
    /**
     * 封装路径信息的类
     */
    private String path; // 路径

    /**
     * 组件信息
     */
    private String component; // 组件

    /**
     * 重定向信息
     */
    private String redirect; // 重定向

    /**
     * 名称信息
     */
    private String name; // 名称

    @Data
    @ToString
    @AllArgsConstructor
    public static class Meta {

        // 标题
        @Schema(description = "路由名称")
        private String title;

        // 图标
        @Schema(description = "路由图标")
        private String icon;

        // 是否隐藏
        @Schema(description = "是否隐藏")
        private boolean hidden;

        // 用户角色列表
        @Schema(description = "用户角色列表")
        private List<String> roles;

        // 是否保持常驻
        @Schema(description = "是否保持常驻")
        private boolean keepAlive;
    }

    @Schema(description = "路由元数据")
    private Meta meta;

    // 子路由
    @Schema(description = "子路由")
    private List<RouteVo> children;
}

获取下拉菜单

  • 封装权限树MenuOptionsVo
@Schema(description ="菜单下拉选项响应对象")
public class MenuOptionsVo {
    /**
     * 选项值
     */
    private Long value;

    /**
     * 选项名称
     */
    private String label;

    /**
     * 子菜单
     */
    @TableField(exist = false)
    private List<MenuOptionsVo> children;
}
  • 获取菜单树
public class MenuTreeVo {

    @Schema(description = "id")
    private Long id;

    @Schema(description = "父级id")
    private Long parentId;

    @Schema(description = "菜单名称")
    private String name;

    @Schema(description = "菜单类型")
    private String type;

    @Schema(description = "菜单路径")
    private String path;

    @Schema(description = "菜单组件")
    private String component;

    @Schema(description = "菜单图标")
    private String icon;

    @Schema(description = "菜单排序")
    private Integer sort;

    @Schema(description = "菜单状态:0-隐藏,1-显示")
    private Integer visible;

    @Schema(description = "菜单权限")
    // sys:user:add
    private String perm;

    @Schema(description = "重定向")
    private String redirect;

    @Schema(description = "子菜单")
    private List<MenuTreeVo> children;
}

角色接口

获取角色分页列表

  • 继承BaseController, 获取分页的pageSize和pageNum,封装PageHelp的startPage方法
  • 封装角色分页请求对象 RolePageDto
  • 封装角色分页列表响应对象 RolePageVo
  • 角色对象通过角色表,用户表,用户角色表关联构建
public class RolePageDto {

    @Schema(description = "角色名称")
    private String name;

    @Schema(description = "角色标识,code")
    private String code;

    @Schema(description = "角色状态")
    private Integer status;
}
public class RolePageVo {

    @Schema(description = "角色ID")
    private Long id;

    @Schema(description = "角色名称")
    private String name;

    @Schema(description = "角色编码")
    private String code;

    @Schema(description = "显示顺序")
    private Integer sort;

    @Schema(description = "状态:0-正常,1-停用")
    private Integer status;

    @Schema(description = "逻辑删除标识(0-未删除;1-已删除)")
    private Integer deleted;

    @Schema(description = "备注")
    private String remark;

    @Schema(description = "创建时间")
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
    private Date createTime;

    @Schema(description = "更新时间")
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
    private Date updateTime;
}

获取角色下拉选项表

  • 封装角色下拉选项对象 OptionsVo

根据roleId获取角色信息

  • 封装RoleForm响应对象

根据roleId获取用户拥有的权限id集合

根据roleId修改角色信息

根据roleId删除角色信息

  • (逻辑删除,修改字段is_deleted为1)

修改角色权限

@Schema(description ="性别、角色下拉选项响应对象")
public class OptionsVo {

    @Schema(description = "选项值")
    private Long value;

    @Schema(description = "选项名称")
    private String label;
}
@Schema(description = "角色表单对象")
@Data
public class RoleForm {

    @Schema(description="角色ID")
    private Long id;

    @Schema(description="角色名称")
    private String name;

    @Schema(description="角色编码")
    private String code;

    @Schema(description="排序")
    private Integer sort;

    @Schema(description="角色状态(1-正常;0-停用)")
    private Integer status;

    @Schema(description = "备注信息")
    private String remark;
}

动态权限校验

实现逻辑

  • 从Security中取出用户信息,获取用户的perms
  • 获取所有的权限集合
  • 判断进入的URL和请求方式是否在权限集合中
  • 若存在则对比获取到的权限与请求中URL以及请求方式来和用户的perms做字符串判断
  • 校验通过

缓存监控接口

  • 获取缓存名称
  • 获取指定name下的所有缓存key
  • 获取指定name下的指定key的缓存信息
  • 清除指定name下的所有缓存信息
  • 清除指定key的缓存
  • 清除整个redis的所有缓存

服务监控接口

  • CPU信息
  • Mem内存信息
  • File磁盘信息
  • JVM信息

字典管理接口

根据typeCode获取字典下拉列表

  • 封装响应对象 OptionsVo

根据code编码获取字典值分页数据

  • 封装响应对象 DictPageVo
  • 封装请求对象 DictPage(继承分页类)

获取所有字典类型列表

  • 封装响应对象 DictTypeVo

新增字典类型

新增字典类型对应的值

修改字典类型

修改字典类型对应的值

删除字典类型

根据code编码删除字典值列表

Swagger部分注解

@TableField: 数据库对应类映射字段注解(entity包)

@Schema: 用于类或属性级别,用于定义数据模型或JSON对象结构。它用于描述类的字段,包括字段名、类型、是否必填、默认值、枚举值、格式限制等

@Operation: 用于方法上的注解

参数校验

  • 引入 spring-boot-starter-validation 依赖
  • 通过注解@Valid的方式进行校验
  • 在需要校验的类中加上判断即可
  • 全局异常捕获MethodArgumentNotValidException进行处理
ResponseCode VALID_ERROR(1002, "参数校验失败"),
/**
 * 处理参数校验异常
 * @param e
 * @return
 */
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public BaseResponse handleValidationExceptions(MethodArgumentNotValidException e) {
    String msg  =e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
    return BaseResponse.fail(ResponseCode.VALID_ERROR.getCode(), msg == null ? ResponseCode.VALID_ERROR.getMsg() : msg);
}
  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在写一个前后端分离后台管理系统时,您可以使用 Spring Boot 作为后端框架, Vue.js 作为前端框架,MyBatis 作为数据访问框架。 首先,您需要在 Spring Boot 中配置 MyBatis,连接到数据库并编写相应的 SQL 语句。然后,您可以编写后端控制器来处理 HTTP 请求,并使用 MyBatis 执行数据库操作。 在前端部分,您可以使用 Vue.js 构建用户界面,并使用 Axios 等库与后端进行交互。当用户在前端界面中进行操作时,Vue.js 将调用相应的函数并发送 HTTP 请求到后端后端控制器将处理请求并返回响应,Vue.js 将使用响应更新前端界面。 总的来说,使用 Spring Boot、Vue.js 和 MyBatis 开发前后端分离后台管理系统是一个不错的选择,它们提供了良好的支持和工具,帮助您快速构建功能丰富、可扩展的后台管理系统。 ### 回答2: 要写一个前后端分离后台管理系统,首先需要明确系统的功能和需求,然后结合Spring Boot、Vue和MyBatis这三个框架进行开发。 1. 后端开发: - 使用Spring Boot搭建后台服务,配置相关依赖和基本的配置。 - 设计数据库表结构,并使用MyBatis进行数据库操作。 - 创建后端接口,包括用户管理、权限管理、数据查询等功能,并使用MyBatis实现相关的数据操作。 - 配置接口的权限验证,使用Spring Security进行登录认证和权限控制。 2. 前端开发: - 使用Vue框架搭建前端界面,并配置相关依赖和基本的配置。 - 设计后台管理系统的页面布局和样式,使用Vue Router进行前端路由管理。 - 实现用户登录和权限验证功能,与后端接口进行通信,使用Axios进行数据请求和响应处理。 - 开发各个功能模块的前端页面,包括用户管理、权限管理、数据查询等,并与后端接口进行数据交互。 3. 前后端协作: - 前后端的数据交互一般使用JSON格式,后端通过Spring Boot提供的@RestController注解,返回JSON格式的数据给前端。 - 前端通过Axios库发送请求给后端接口,获取数据并进行处理展示。 - 前后端对接口的定义和数据格式进行约定,确保数据的有效性和一致性。 - 前后端进行联调和测试,确认系统正常运行并满足需求。 总之,使用Spring Boot、Vue和MyBatis可以很好地实现一个前后端分离后台管理系统。通过后端提供接口和数据服务,前端实现页面展示和用户操作,两者通过数据交互实现系统功能。这种架构可以提高开发效率和可维护性,实现前后端的解耦和灵活性。 ### 回答3: 将SpringBoot与Vue和MyBatis结合起来构建一个前后端分离后台管理系统可以分为以下几个步骤: 1. 创建SpringBoot项目:首先,我们需要创建一个SpringBoot项目作为后端服务。可以使用Spring Initializr快速搭建项目基础结构,并且添加所需的依赖,如Spring Web、Spring Data JPA、MyBatis等。 2. 设计数据库结构:根据后台管理系统的需求,设计数据库表结构,并使用MyBatis创建对应的实体类和Mapper接口。 3. 编写后端API:在SpringBoot项目中,编写对应的Controller类,实现接口的定义和业务逻辑。通过注解配置路由信息,用于定义API的访问路径和请求方式,同时接收前端传递的参数并返回相应的结果。 4. 创建Vue项目:使用Vue脚手架工具(例如Vue CLI)创建一个新的Vue项目作为前端界面。在项目初始化中选择自己喜欢的UI框架(如ElementUI),并安装需要的插件和依赖。 5. 编写前端页面:根据后台管理系统的需求,设计并编写相应的页面组件。利用Vue的组件化开发,将整个页面划分为不同的组件,并进行组件的构建和样式的设计。 6. 实现前后端数据交互:在Vue项目中,使用axios或者其他HTTP请求库与后端建立请求连接,发送API请求,并接收后端返回的数据。可以使用Vue的生命周期钩子函数或者Vuex来处理数据的请求和响应。 7. 页面路由与导航:根据后台管理系统的需求,在Vue项目中设置路由信息,配置页面导航和跳转功能。可以利用Vue Router进行路由的管理和操作。 8. 测试和部署:完成以上步骤后,进行系统的单元测试和集成测试,并进行系统的部署和上线。 通过以上步骤,就可以使用SpringBoot、Vue和MyBatis构建一个前后端分离后台管理系统。前端通过Vue实现了页面的展示和交互逻辑,后端通过SpringBoot提供了API的定义和业务处理,而MyBatis则负责与数据库之间的交互操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值