java之springboot+springsecurity+vue实现后台管理系统的开发三系统权限(代码片段)

蓝盒子itbluebox 蓝盒子itbluebox     2022-11-29     508

关键词:

Java 之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发【一、前端】跳转
Java 之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发【二、后端】跳转
Java 之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发【三、系统权限】跳转

Java 之SpringBoot+Vue实现后台管理系统的开发项目源代码

https://download.csdn.net/download/qq_44757034/86246453

一、权限缓存

因为上面我在获取用户权限那里添加了个缓存,这时候问题来了,

就是权限缓存的实时更新问题,
比如当后台更新某个管理员的权限角色信息的时候如果权限缓存信息没有实时更新,

就会出现操作无效的问题,那么我们现在点定义几个方法,

用于清除某个用户或角色或者某个菜单的权限的方法:

@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService 
    @Autowired
    private SysRoleService sysUserService;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    @Lazy
    private SysMenuService sysMenuService;
    @Autowired
    private RedisUtil redisUtil;
    @Override
    public SysUser getByUserName(String username) 
        return getOne(new QueryWrapper<SysUser>().eq("username",username));
    
    @Override
    public String getUserAuthorityInfo(Long userId) 
        SysUser sysUser = sysUserMapper.selectById(userId);
        //通过用户id获取对应的角色信息
        String authority = null;
        if(redisUtil.hasKey("GrantedAuthority:"+sysUser.getUsername()))
            authority = (String) redisUtil.get("GrantedAuthority:" + sysUser.getUsername());
        else 
            //获取角色编码
            //通过用户id,查出对应的用户角色id,通过角色id查询,对应用户的角色信息
            List<SysRole> roles = sysUserService.list(new QueryWrapper<SysRole>().inSql("id", "select role_id from sys_user_role where user_id = " + userId));
            if(roles.size() > 0)
                String roleCode = roles.stream().map(r -> "ROLE_"+r.getCode()).collect(Collectors.joining(","));
                authority = roleCode.concat(",");
            
            //获取菜单操作权限
            List<Long> menuIds = sysUserMapper.getNavMenuIds(userId);
            if(menuIds.size() > 0)
                List<SysMenu> sysMenus = sysMenuService.listByIds(menuIds);
                String menuPerms = sysMenus.stream().map(m -> m.getPerms()).collect(Collectors.joining(","));
                authority = authority.concat(menuPerms);
            
            redisUtil.set("GrantedAuthority:"+sysUser.getUsername(),authority,60 * 60);
        
        return authority;
    

添加断点


登录以后发送请求

第一次访问:Redis当中的权限信息为空

第二次访问:Redis对应的权限信息不为空

完善权限其他方法

    void clearUserAuthorityInfo(String username);

    void clearUserAuthorityInfoByRoleId(Long roleId);

    void clearUserAuthorityInfoByMenuId(Long menuId);

完善,设置清楚用户的权限信息,在更新对应的角色和用户信息的时候
SysUserServiceImpl

@Override
    public String getUserAuthorityInfo(Long userId) 
        SysUser sysUser = sysUserMapper.selectById(userId);
        //通过用户id获取对应的角色信息
        String authority = null;
        if(redisUtil.hasKey("GrantedAuthority:"+sysUser.getUsername()))
            authority = (String) redisUtil.get("GrantedAuthority:" + sysUser.getUsername());
        else 
            //获取角色编码
            //通过用户id,查出对应的用户角色id,通过角色id查询,对应用户的角色信息
            List<SysRole> roles = sysUserService.list(new QueryWrapper<SysRole>().inSql("id", "select role_id from sys_user_role where user_id = " + userId));
            if(roles.size() > 0)
                String roleCode = roles.stream().map(r -> "ROLE_"+r.getCode()).collect(Collectors.joining(","));
                authority = roleCode.concat(",");
            
            //获取菜单操作权限
            List<Long> menuIds = sysUserMapper.getNavMenuIds(userId);
            if(menuIds.size() > 0)
                List<SysMenu> sysMenus = sysMenuService.listByIds(menuIds);
                String menuPerms = sysMenus.stream().map(m -> m.getPerms()).collect(Collectors.joining(","));
                authority = authority.concat(menuPerms);
            
            redisUtil.set("GrantedAuthority:"+sysUser.getUsername(),authority,60 * 60);
        
        return authority;
    

    @Override
    public void clearUserAuthorityInfo(String username) 
        redisUtil.del("GrantedAuthority:"+username);
    

    @Override
    public void clearUserAuthorityInfoByRoleId(Long roleId) 
        List<SysUser> sysUsers = this.list(new QueryWrapper<SysUser>()
                .inSql("id", "select user_id from sys_user_role where role_id = " + roleId));
        sysUsers.forEach(u ->
            this.clearUserAuthorityInfo(u.getUsername());
        );
    

    @Override
    public void clearUserAuthorityInfoByMenuId(Long menuId) 
       List<SysUser> sysUsers = sysUserMapper.listByMenuId(menuId);
        sysUsers.forEach(u ->
            this.clearUserAuthorityInfo(u.getUsername());
        );
    

    List<SysUser> listByMenuId(Long menuId);

 <select id="listByMenuId" resultType="cn.itbluebox.springbootadminvue.entity.SysUser">
        SELECT DISTINCT
            su.*
        FROM
            sys_user_role ur
                LEFT JOIN sys_role_menu rm ON ur.role_id = rm.role_id
                LEFT JOIN sys_user su on ur.user_id = su.id
        WHERE
            rm.menu_id = #menuId
    </select>

完善
SysUserServiceImpl

    @Override
    public void clearUserAuthorityInfoByMenuId(Long menuId) 
       List<SysUser> sysUsers = sysUserMapper.listByMenuId(menuId);
        sysUsers.forEach(u ->
            this.clearUserAuthorityInfo(u.getUsername());
        );
    

二、退出数据返回

1、创建JwtLogoutSuccessHandler


@Component
public class JwtLogoutSuccessHandler implements LogoutSuccessHandler 

    @Autowired
    JwtUtils jwtUtils;

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException 
        if(authentication != null)
            new SecurityContextLogoutHandler().logout(request,response,authentication);
        
        response.setContentType("application/json;charset=UTF-8");
        ServletOutputStream outputStream = response.getOutputStream();

        response.setHeader(jwtUtils.getHeader(), null);

        Result result = Result.success("成功");

        outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));

        outputStream.flush();
        outputStream.close();
    


2、完善SecurityConfig

   @Autowired
    private JwtLogoutSuccessHandler jwtLogoutSuccessHandler;
   .and()
        .logout()
        .logoutSuccessHandler(jwtLogoutSuccessHandler)

三、前后端对接(菜单)

1、前后端对接的问题

因为我们之前开发前端的时候,我们都是使用mockjs返回随机数据的,
一般来说问题不会很大,我就怕有些同学再去掉mock之后,和后端对接却显示不出数据,这就尴尬了。
这时候我建议你去看我的开发视频哈。

后面因为都是接口的增删改查,难度其实不是特别大,所以大部分时候我都会直接贴代码,

2、菜单接口开发

我们先来开发菜单的接口,

因为这3个表:用户表、角色表、菜单表,才有菜单表是不需要通过其他表来获取信息的。

比如用户需要关联角色,角色需要关联菜单,而菜单不需要主动关联其他表。

因此菜单表的增删改查是最简单的。

再回到我们的前端项目,登录完成之后我们通过WT获取项目的导航菜单和权限,

那么接下来我们就先编写这个接口。

获取菜单导航和权限的链接是/sys/menu/nav,然后我们的菜单导航的json数据应该是这样的:

删除下面两个接口,中间表的Controller是自动生成的


BaseController


    @Autowired
    SysUserService sysUserService;

    @Autowired
    SysRoleService sysRoleService;

    @Autowired
    SysMenuService sysMenuService;

    @Autowired
    SysUserRoleService sysUserRoleService;

    @Autowired
    SysRoleMenuService sysRoleMenuService;




@Data
public class SysMenuDto implements Serializable 

    private Long id;
    private String name;
    private String title;
    private String icon;
    private String path;
    private String component;
    private List<SysMenuDto> children = new ArrayList<>();



@RestController
@RequestMapping("/sys/menu")
public class SysMenuController extends BaseController 

    @GetMapping("/nav")
    public Result nav(Principal principal)

        SysUser sysUser = sysUserService.getByUserName(principal.getName());

        //获取权限信息
        String authorityInfo = sysUserService.getUserAuthorityInfo(sysUser.getId());

        String[] authorityInfoArray = StringUtils.tokenizeToStringArray(authorityInfo, "");

        //获取导航栏信息
        List<SysMenuDto> navs = sysMenuService.getCurrentUserNav();

        return Result.success(
                MapUtil.builder()
                        .put("authoritys",authorityInfoArray)
                        .put("nav",navs)
                        .map()
        );
    


public interface SysMenuService extends IService<SysMenu> 
    List<SysMenuDto> getCurrentUserNav();

完善SysMenu

   /**
     * 排序
     */
    @TableField("orderNum")
    private Integer orderNum;

    @TableField(exist = false)
    private List<SysMenu> children = new ArrayList<>();

完善SysMenuServiceImpl

    private List<SysMenu> buildTreeMenu(List<SysMenu> menus) 
        List<SysMenu> finalMenus = new ArrayList<>();
        //先各自寻找到自己的孩子
        for (SysMenu menu:menus)
            for(SysMenu e:menus)
                if(menu.getId().equals(e.getParentId()))
                    menu.getChildren().add(e);
                
            
            if(menu.getParentId() == 0)
                finalMenus.add(menu);
            
        
        log.info(JSONUtil.toJsonStr(finalMenus));
        //提取出父亲
        return finalMenus;
    
    private List<SysMenuDto> convert(List<SysMenu> menuTree)
        List<SysMenuDto> menuDtos = new ArrayList<>();
        menuTree.forEach(m ->
            SysMenuDto dto = new SysMenuDto();
            dto.setId(m.getId());
            dto.setName(m.getPerms());
            dto.setTitle(m.getName());
            dto.setComponent(m.getComponent());
            dto.setPath(m.getPath());
            if(m.getChildren().size() > 0)
                //子节点调用当前方法进行再次替换
                dto.setChildren(convert(m.getChildren()));
            
            menuDtos.add(dto);
        );
        return menuDtos;
    

3、运行测试


http://localhost:8081/sys/menu/nav

Authorization

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY1NjU1ODY4NywiZXhwIjoxNjU3MTYzNDg3fQ.Nso0BloTp0eggRU2eyMJdkY27ZBow8OfoZWcHSk2USWNv9jtu1L_e9bvnBNmm_82hzr8JcpKFNE3U6wvI0m2xw


数据不太全面,在这里我们添加一些数据,执行一些SQL语句

/*
Navicat MySQL Data Transfer

Source Server         : pro-markerhub
Source Server Version : 50727
Source Host           : 129.204.23.53:3306
Source Database       : vueadmin

Target Server Type    : MYSQL
Target Server Version : 50727
File Encoding         : 65001

Date: 2021-01-30 21:02:31
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for sys_menu
-- ----------------------------
java框架之springboot二:springboot配置获取

java框架之Springboot二:SpringBoot配置获取resources文件夹中的目录结构:static:保存所有的静态资源;js,css,imagestemplates:保存所有的模板页面;application.properties:配置文件,可以修改一些默认配置配置文件... 查看详情

java之springboot入门到精通idea版springboot原理分析,springboot监控(一篇文章精通系列)下(代码片段)

目录Java之SpringBoot入门到精通【IDEA版】(一篇文章精通系列)【上】Java之SpringBoot入门到精通【IDEA版】SpringBoot整合其他框架【Junit,Redis,MyBatis】(一篇文章精通系列)【中】Java之SpringBoot入门到精通【IDEA版】SpringBo... 查看详情

java之springboot+springsecurity+vue实现后台管理系统的开发三系统权限(代码片段)

Java之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发【一、前端】跳转Java之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发【二、后端】跳转Java之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发【三、系统权限... 查看详情

springboot之日志记录

SpringBoot之日志记录SpringBoot支持集成Java世界主流的日志库。如果对于Java日志库不熟悉,可以参考:细说Java主流日志工具库关键词:log4j,log4j2,logback,slf4j日志格式控制台输出彩色打印文件输出日志级别日志组日志配置文件SpringBoot... 查看详情

java框架之springboot三:springboot自定义配置一

java框架之Springboot三:SpringBoot自定义配置一私有化配置文件刚才我们介绍了在主配置文件汇中配置对应的文件,如果我们想要自定义配置文件该怎么处理呢?现在就要给大家介绍我们的@PropertySource注解。@PropertyS... 查看详情

springboot.07.springboot切面编程之aop(代码片段)

SpringBoot.07.SpringBoot切面编程之AOP前言AOP介绍概念纵向集成体系横向抽取机制相关术语AOP使用小试牛刀1.新建Module2.项目配置3.pom.xml4.MyAspect.java5.测试5.1正常运行5.2方法中抛出异常注解方式1.MyAspectAnnotations.java2.MyAspect2.java3.UserServiceIm... 查看详情

springboot.07.springboot切面编程之aop(代码片段)

SpringBoot.07.SpringBoot切面编程之AOP前言AOP介绍概念纵向集成体系横向抽取机制相关术语AOP使用小试牛刀1.新建Module2.项目配置3.pom.xml4.MyAspect.java5.测试5.1正常运行5.2方法中抛出异常注解方式1.MyAspectAnnotations.java2.MyAspect2.java3.UserServiceIm... 查看详情

springboot.07.springboot切面编程之aop(代码片段)

SpringBoot.07.SpringBoot切面编程之AOP前言AOP介绍概念纵向集成体系横向抽取机制相关术语AOP使用小试牛刀1.新建Module2.项目配置3.pom.xml4.MyAspect.java5.测试5.1正常运行5.2方法中抛出异常注解方式1.MyAspectAnnotations.java2.MyAspect2.java3.UserServiceIm... 查看详情

java面试之springboot篇

目录一、什么是SpringBoot?二、SpringBoot有哪些优点?三、如何在自定义端口上运行SpringBoot应用程序?四、什么是YAML?五、SpringBoot的核心配置文件有哪几个?它们的区别是什么?六、SpringBoot的配置文件有哪... 查看详情

java面试之springboot篇

目录一、什么是SpringBoot?二、SpringBoot有哪些优点?三、如何在自定义端口上运行SpringBoot应用程序?四、什么是YAML?五、SpringBoot的核心配置文件有哪几个?它们的区别是什么?六、SpringBoot的配置文件有哪... 查看详情

[interview]java面试宝典系列之springboot(代码片段)

文章目录1.说说你对SpringBoot的理解2.SpringBootStarter有什么用?3.介绍SpringBoot的启动流程4.SpringBoot项目是如何导入包的?5.请描述SpringBoot自动装配的过程6.说说你对SpringBoot注解的了解1.说说你对SpringBoot的理解从本质上来说... 查看详情

java之springboot+springsecurity+vue实现后台管理系统的开发二后端(代码片段)

Java之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发【一、前端】跳转Java之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发【二、后端】跳转Java之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发【三、系统权限... 查看详情

java进阶之springboot

...置开发和构建,打包和部署应用程序----------创建:1.使用SpringBootCLI工具2.使用SpringSTSIDE3.使用SpringIni 查看详情

java框架技术之十八节springboot课件上手教程(代码片段)

学习目标了解SpringBoot的作用掌握java配置的方式了解SpringBoot自动配置原理掌握SpringBoot的基本使用了解Thymeleaf的基本使用1.了解SpringBoot在这一部分,我们主要了解以下3个问题:什么是SpringBoot为什么要学习SpringBootSpringBoot的... 查看详情

java框架技术之十八节springboot课件上手教程(代码片段)

学习目标了解SpringBoot的作用掌握java配置的方式了解SpringBoot自动配置原理掌握SpringBoot的基本使用了解Thymeleaf的基本使用1.了解SpringBoot在这一部分,我们主要了解以下3个问题:什么是SpringBoot为什么要学习SpringBootSpringBoot的... 查看详情

java之springcloud微服务的开源配置中心apollo(第四个阶段)springboot项目实现商品服务器端调用(代码片段)

...ava之SpringCloud微服务搭建(第一个阶段)【一】【SpringBoot项目实现商品服务器端是调用】Java之SpringCloud微服务Eureka(第一个阶段)【二】【SpringBoot项目实现商品服务器端是调用】Java之SpringCloud微服务搭建Ribbon࿰... 查看详情

springboot框架学习学前掌握之重要注解-通过java的配置方式进行配置spring

...点注解理解声明:本文是《凯哥陪你学系列-框架学习之springboot框架学习》中springboot框架学习学前掌握之重要注解(2)-通过java的配置方式进行配置spring.在上一节《springboot框架学习学前掌握之重要注解(1)-spring的java配置方式》我们... 查看详情

springboot框架学习学前掌握之重要注解-通过java的配置方式进行配置spring

...点注解理解声明:本文是《凯哥陪你学系列-框架学习之springboot框架学习》中springboot框架学习学前掌握之重要注解(2)-通过java的配置方式进行配置spring.在上一节《springboot框架学习学前掌握之重要注解(1)-spring的java配置方式》我们... 查看详情