Java 之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发三系统权限

Posted 蓝盒子itbluebox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发三系统权限相关的知识,希望对你有一定的参考价值。

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+SpringSecurity+Vue实现后台管理系统的开发三系统权限的主要内容,如果未能解决你的问题,请参考以下文章

Java 之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发三系统权限

Java之Spring Boot入门到精通IDEA版SpringBoot原理分析,SpringBoot监控(一篇文章精通系列)下

Java 之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发一前端

SpringBoot.07.SpringBoot切面编程之AOP

SpringBoot.07.SpringBoot切面编程之AOP

SpringBoot.07.SpringBoot切面编程之AOP