diff --git a/agileboot-common/wol-common-satoken/src/main/java/com/agileboot/common/satoken/config/SaTokenMvcConfiguration.java b/agileboot-common/wol-common-satoken/src/main/java/com/agileboot/common/satoken/config/SaTokenMvcConfiguration.java index eef57d3..f53e16e 100644 --- a/agileboot-common/wol-common-satoken/src/main/java/com/agileboot/common/satoken/config/SaTokenMvcConfiguration.java +++ b/agileboot-common/wol-common-satoken/src/main/java/com/agileboot/common/satoken/config/SaTokenMvcConfiguration.java @@ -40,6 +40,7 @@ public class SaTokenMvcConfiguration implements WebMvcConfigurer { public SaServletFilter getGlobleSaServletFilter() { return new SaServletFilter() .addInclude("/**").addExclude("/favicon.ico") + .addExclude("/auth/getConfig", "/captcha/code") .setAuth(obj -> { SaRouter.match("/**", "/auth/login", StpUtil::checkLogin); }) diff --git a/agileboot-common/wol-common-satoken/src/main/java/com/agileboot/common/satoken/pojo/LoginUser.java b/agileboot-common/wol-common-satoken/src/main/java/com/agileboot/common/satoken/pojo/LoginUser.java index 51b0cec..cb32599 100644 --- a/agileboot-common/wol-common-satoken/src/main/java/com/agileboot/common/satoken/pojo/LoginUser.java +++ b/agileboot-common/wol-common-satoken/src/main/java/com/agileboot/common/satoken/pojo/LoginUser.java @@ -135,6 +135,11 @@ public class LoginUser implements Serializable { */ private String deviceType; + /** + * 是否是超级管理员 + */ + private Integer isAdmin; + /** * 获取登录id */ diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/ISysMenuService.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/ISysMenuService.java index 369a354..16f4cb7 100644 --- a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/ISysMenuService.java +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/ISysMenuService.java @@ -3,6 +3,7 @@ package com.agileboot.system.menu.service; import cn.hutool.core.lang.tree.Tree; import com.agileboot.common.satoken.pojo.LoginUser; import com.agileboot.system.menu.dto.*; +import com.agileboot.system.menu.vo.RouterVO; import java.util.List; @@ -20,4 +21,6 @@ public interface ISysMenuService { void remove(Long menuId); List getMenuIdsByRoleId(Long roleId); + + List getRouterTree(LoginUser loginUser); } diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/impl/SysMenuServiceImpl.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/impl/SysMenuServiceImpl.java index 261cfa1..c8d432b 100644 --- a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/impl/SysMenuServiceImpl.java +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/menu/service/impl/SysMenuServiceImpl.java @@ -1,9 +1,11 @@ package com.agileboot.system.menu.service.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.lang.tree.TreeNodeConfig; import cn.hutool.core.lang.tree.TreeUtil; import com.agileboot.common.core.enums.common.MenuTypeEnum; +import com.agileboot.common.core.enums.common.StatusEnum; import com.agileboot.common.core.exception.BizException; import com.agileboot.common.core.exception.error.ErrorCode; import com.agileboot.common.core.utils.jackson.JacksonUtil; @@ -12,12 +14,14 @@ import com.agileboot.system.menu.dto.*; import com.agileboot.system.menu.entity.SysMenu; import com.agileboot.system.menu.mapper.SysMenuMapper; import com.agileboot.system.menu.service.ISysMenuService; +import com.agileboot.system.menu.vo.RouterVO; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import java.util.Comparator; +import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -114,13 +118,68 @@ public class SysMenuServiceImpl extends ServiceImpl impl return this.baseMapper.selectMenuIdsByRoleId(roleId); } + @Override + public List getRouterTree(LoginUser loginUser) { + List> trees = buildMenuEntityTree(loginUser); + return buildRouterTree(trees); + } + + public List> buildMenuEntityTree(LoginUser loginUser) { + List allMenus; + if (loginUser.getIsAdmin() == 1) { + allMenus = super.list(); + } else { + allMenus = this.baseMapper.selectMenuListByUserId(loginUser.getUserId()); + } + + // 传给前端的路由排除掉按钮和停用的菜单 + List noButtonMenus = allMenus.stream() + .filter(menu -> !menu.getIsButton()) + .filter(menu-> StatusEnum.ENABLE.getValue().equals(menu.getStatus())) + .collect(Collectors.toList()); + + TreeNodeConfig config = new TreeNodeConfig(); + // 默认为id 可以不设置 + config.setIdKey("menuId"); + + return TreeUtil.build(noButtonMenus, 0L, config, (menu, tree) -> { + // 也可以使用 tree.setId(dept.getId());等一些默认值 + tree.setId(menu.getMenuId()); + tree.setParentId(menu.getParentId()); + // TODO 可以取meta中的rank来排序 +// tree.setWeight(menu.getRank()); + tree.putExtra("entity", menu); + }); + + } + + + public List buildRouterTree(List> trees) { + List routers = new LinkedList<>(); + if (CollUtil.isNotEmpty(trees)) { + for (Tree tree : trees) { + Object entity = tree.get("entity"); + if (entity != null) { + RouterVO routerDTO = new RouterVO((SysMenu) entity); + List> children = tree.getChildren(); + if (CollUtil.isNotEmpty(children)) { + routerDTO.setChildren(buildRouterTree(children)); + } + routers.add(routerDTO); + } + + } + } + return routers; + } + /** * 构建前端所需要树结构 * * @param menus 菜单列表 * @return 树结构列表 */ - public List> buildMenuTreeSelect(List menus) { + private List> buildMenuTreeSelect(List menus) { TreeNodeConfig config = new TreeNodeConfig(); //默认为id可以不设置 config.setIdKey("menuId"); diff --git a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/user/service/impl/SysUserServiceImpl.java b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/user/service/impl/SysUserServiceImpl.java index 7d41acc..6d04921 100644 --- a/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/user/service/impl/SysUserServiceImpl.java +++ b/agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/user/service/impl/SysUserServiceImpl.java @@ -44,6 +44,7 @@ public class SysUserServiceImpl extends ServiceImpl impl loginUser.setUsername(sysUser.getUsername()); loginUser.setNickname(sysUser.getNickname()); loginUser.setPassword(sysUser.getPassword()); + loginUser.setIsAdmin(sysUser.getIsAdmin()); return loginUser; } diff --git a/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/controller/AuthController.java b/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/controller/AuthController.java index 46305c8..d9a20ca 100644 --- a/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/controller/AuthController.java +++ b/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/controller/AuthController.java @@ -2,25 +2,30 @@ package com.agileboot.auth.controller; import cn.dev33.satoken.annotation.SaIgnore; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.extra.spring.SpringUtil; import com.agileboot.auth.pojo.dto.LoginBody; import com.agileboot.auth.pojo.dto.RegisterBody; +import com.agileboot.auth.pojo.vo.ConfigVO; import com.agileboot.auth.pojo.vo.LoginVO; import com.agileboot.auth.service.IAuthStrategy; import com.agileboot.auth.service.SysLoginService; import com.agileboot.common.core.constant.Constants; import com.agileboot.common.core.core.R; import com.agileboot.common.core.utils.ValidatorUtils; +import com.agileboot.common.satoken.pojo.LoginUser; +import com.agileboot.common.satoken.utils.LoginHelper; import com.agileboot.system.client.service.ISysClientService; import com.agileboot.system.client.vo.SysClientVO; +import com.agileboot.system.menu.service.ISysMenuService; +import com.agileboot.system.menu.vo.RouterVO; import com.alibaba.fastjson2.JSONObject; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.List; /** * 认证 @@ -36,6 +41,7 @@ public class AuthController { private final SysLoginService loginService; private final ISysClientService sysClientService; + private final ISysMenuService sysMenuService; /** * 登录方法 @@ -63,6 +69,20 @@ public class AuthController { return R.ok(loginVo); } + /** + * 获取系统的内置配置 + * + * @return 配置信息 + */ + @GetMapping("/getConfig") + public R getConfig() { +// ConfigVO vo = loginService.getConfig(); + ConfigVO configVO = new ConfigVO(); + String property = SpringUtil.getProperty("security.captcha.enabled"); + configVO.setIsCaptchaOn(Boolean.parseBoolean(property)); + return R.ok(configVO); + } + /** * 退出登录 */ @@ -80,4 +100,16 @@ public class AuthController { loginService.register(user); return R.ok(); } + + /** + * 获取用户对应的菜单路由 用于动态生成路由 + * TODO 如果要在前端开启路由缓存的话 需要在ServerConfig.json 中 设置CachingAsyncRoutes=true 避免一直重复请求路由接口 + * @return 路由信息 + */ + @GetMapping("/getRouters") + public R> getRouters() { + LoginUser loginUser = LoginHelper.getLoginUser(); + List routerTree = sysMenuService.getRouterTree(loginUser); + return R.ok(routerTree); + } } diff --git a/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/controller/CaptchaController.java b/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/controller/CaptchaController.java index 3715018..913c719 100644 --- a/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/controller/CaptchaController.java +++ b/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/controller/CaptchaController.java @@ -1,5 +1,6 @@ package com.agileboot.auth.controller; +import cn.dev33.satoken.annotation.SaIgnore; import cn.hutool.captcha.AbstractCaptcha; import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.core.util.IdUtil; @@ -21,6 +22,7 @@ import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.time.Duration; @@ -32,8 +34,10 @@ import java.time.Duration; */ @Slf4j @Validated +@SaIgnore @RequiredArgsConstructor -@RestController("/captcha") +@RestController +@RequestMapping("/captcha") public class CaptchaController { private final CaptchaProperties captchaProperties; @@ -47,11 +51,11 @@ public class CaptchaController { CaptchaVO captchaVo = new CaptchaVO(); boolean captchaEnabled = captchaProperties.getEnabled(); if (!captchaEnabled) { - captchaVo.setCaptchaEnabled(false); + captchaVo.setIsCaptchaOn(false); return R.ok(captchaVo); } - CaptchaController proxy = (CaptchaController) AopContext.currentProxy(); - return R.ok(proxy.getCodeImpl()); +// CaptchaController proxy = (CaptchaController) AopContext.currentProxy(); + return R.ok(this.getCodeImpl()); } /** diff --git a/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/pojo/form/PasswordLoginBody.java b/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/pojo/form/PasswordLoginBody.java index 2dd8868..6714e34 100644 --- a/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/pojo/form/PasswordLoginBody.java +++ b/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/pojo/form/PasswordLoginBody.java @@ -26,7 +26,7 @@ public class PasswordLoginBody extends LoginBody { * 用户密码 */ @NotBlank(message = "Password cannot be empty") - @Length(min = 5, max = 30, message = "user.password.length.valid") +// @Length(min = 5, max = 30, message = "user.password.length.valid") private String password; } diff --git a/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/pojo/vo/CaptchaVO.java b/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/pojo/vo/CaptchaVO.java index 763fe62..4e16b1e 100644 --- a/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/pojo/vo/CaptchaVO.java +++ b/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/pojo/vo/CaptchaVO.java @@ -13,7 +13,7 @@ public class CaptchaVO { /** * 是否开启验证码 */ - private Boolean captchaEnabled = true; + private Boolean isCaptchaOn = true; private String uuid; diff --git a/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/pojo/vo/ConfigVO.java b/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/pojo/vo/ConfigVO.java new file mode 100644 index 0000000..c278cc2 --- /dev/null +++ b/agileboot-system/wol-auth/src/main/java/com/agileboot/auth/pojo/vo/ConfigVO.java @@ -0,0 +1,8 @@ +package com.agileboot.auth.pojo.vo; + +import lombok.Data; + +@Data +public class ConfigVO { + private Boolean isCaptchaOn; +} diff --git a/wol-domain/src/main/java/com/agileboot/system/menu/vo/RouterVO.java b/wol-domain/src/main/java/com/agileboot/system/menu/vo/RouterVO.java new file mode 100644 index 0000000..d186f2a --- /dev/null +++ b/wol-domain/src/main/java/com/agileboot/system/menu/vo/RouterVO.java @@ -0,0 +1,80 @@ +package com.agileboot.system.menu.vo; + +import com.agileboot.common.core.utils.jackson.JacksonUtil; +import com.agileboot.system.menu.dto.MetaDTO; +import com.agileboot.system.menu.entity.SysMenu; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.google.common.collect.Lists; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 动态路由信息 + * 必须加上@JsonInclude(Include.NON_NULL)的注解 否则传null值给Vue动态路由渲染时会出错 + * + * @author valarchie + */ +@JsonInclude(Include.NON_NULL) +@Data +@NoArgsConstructor +public class RouterVO { + + public RouterVO(SysMenu entity) { + if (entity != null) { + this.name = entity.getRouterName(); + this.path = entity.getPath(); + // 暂时不需要component +// this.component = entity.getComponent(); +// this.rank = entity.getRank(); +// this.redirect = entity.getRedirect(); + if (JacksonUtil.isJson(entity.getMetaInfo())) { + this.meta = JacksonUtil.from(entity.getMetaInfo(), MetaDTO.class); + } else { + this.meta = new MetaDTO(); + } + this.meta.setAuths(Lists.newArrayList(entity.getPermission())); + } + } + + /** + * 路由名字 根据前端的要求 必须唯一 + * 并按照前端项目的推荐 这个Name最好和组件的Name一样 使用菜单表中的router_name + * TODO 这里后端需要加校验 + */ + private String name; + + /** + * 路由路径地址 + */ + private String path; + + /** + * 路由重定向 + */ + private String redirect; + + /** + * 组件地址 + */ + private String component; + + /** + * 一级菜单排序值(排序仅支持一级菜单) + */ + private Integer rank; + + + /** + * 其他元素 + */ + private MetaDTO meta; + + /** + * 子路由 + */ + private List children; + +}