forked from github/cool-admin-java
feat: 模块注册自动创建Admin菜单 + Admin组织切换生成新JWT
- AppModuleServiceImpl: 模块注册时自动扫描Controller创建菜单树,回写menuIds - AppOrgServiceImpl: Admin切换组织生成新JWT(含新tenantId);新增listForSwitch方法 - AdminAppOrgController: switchOrg返回token;新增/admin/org/listForSwitch端点 - AppOrgService: 接口增加listForSwitch声明 - AppOrgAuthFilter: proxy改为agent(moduleKey与包名一致)
This commit is contained in:
@@ -34,7 +34,7 @@ public class AppOrgAuthFilter extends OncePerRequestFilter {
|
||||
"/app/book/", "book",
|
||||
"/app/ticket/", "ticket",
|
||||
"/app/product/", "product",
|
||||
"/app/agent/", "proxy"
|
||||
"/app/agent/", "agent"
|
||||
);
|
||||
|
||||
@Override
|
||||
|
||||
@@ -63,7 +63,13 @@ public class AdminAppOrgController extends BaseController<AppOrgService, AppOrgE
|
||||
public R switchOrg(@RequestBody JSONObject requestParams) {
|
||||
Long orgId = requestParams.getLong("orgId");
|
||||
Long userId = com.cool.core.util.CoolSecurityUtil.getCurrentUserId();
|
||||
appOrgService.switchOrg(userId, orgId, true);
|
||||
return R.ok();
|
||||
return R.ok(appOrgService.switchOrg(userId, orgId, true));
|
||||
}
|
||||
|
||||
@Operation(summary = "获取可切换的组织列表")
|
||||
@PostMapping("/listForSwitch")
|
||||
public R listForSwitch() {
|
||||
Long userId = com.cool.core.util.CoolSecurityUtil.getCurrentUserId();
|
||||
return R.ok(appOrgService.listForSwitch(userId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,4 +13,6 @@ public interface AppOrgService extends BaseService<AppOrgEntity> {
|
||||
void authorizeModules(Long orgId, List<String> moduleKeys);
|
||||
|
||||
Dict switchOrg(Long userId, Long orgId, boolean isAdmin);
|
||||
|
||||
List<AppOrgEntity> listForSwitch(Long userId);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,134 @@
|
||||
package com.cool.modules.org.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.cool.core.base.BaseServiceImpl;
|
||||
import com.cool.core.base.ModifyEnum;
|
||||
import com.cool.core.util.CoolSecurityUtil;
|
||||
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
|
||||
import com.cool.modules.base.mapper.sys.BaseSysMenuMapper;
|
||||
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
||||
import com.cool.modules.org.mapper.AppModuleMapper;
|
||||
import com.cool.modules.org.entity.AppModuleEntity;
|
||||
import com.cool.modules.org.service.AppModuleService;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AppModuleServiceImpl extends BaseServiceImpl<AppModuleMapper, AppModuleEntity> implements
|
||||
AppModuleService {
|
||||
|
||||
private final BaseSysMenuMapper baseSysMenuMapper;
|
||||
private final BaseSysPermsService baseSysPermsService;
|
||||
|
||||
@Override
|
||||
public void modifyAfter(JSONObject requestParams, AppModuleEntity entity, ModifyEnum type) {
|
||||
if (type == ModifyEnum.ADD) {
|
||||
createMenusForModule(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private void createMenusForModule(AppModuleEntity module) {
|
||||
String moduleKey = module.getModuleKey();
|
||||
if (StrUtil.isBlank(moduleKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String basePackage = "com.cool.modules." + moduleKey + ".controller.admin";
|
||||
Set<Class<?>> controllerClasses = ClassUtil.scanPackageBySuper(basePackage, Object.class);
|
||||
|
||||
if (controllerClasses.isEmpty()) {
|
||||
log.info("[AppModuleService] 未找到模块 {} 的Admin Controller,跳过菜单创建", moduleKey);
|
||||
return;
|
||||
}
|
||||
|
||||
BaseSysMenuEntity dirMenu = new BaseSysMenuEntity();
|
||||
dirMenu.setName(module.getName());
|
||||
dirMenu.setType(0);
|
||||
dirMenu.setIcon(module.getIcon());
|
||||
dirMenu.setRouter("/" + moduleKey);
|
||||
dirMenu.setOrderNum(0);
|
||||
dirMenu.setKeepAlive(true);
|
||||
dirMenu.setIsShow(true);
|
||||
baseSysMenuMapper.insertSelective(dirMenu);
|
||||
|
||||
List<Long> menuIds = new ArrayList<>();
|
||||
menuIds.add(dirMenu.getId());
|
||||
|
||||
for (Class<?> controllerClass : controllerClasses) {
|
||||
String controllerName = controllerClass.getSimpleName();
|
||||
if (!controllerName.startsWith("Admin")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String entityPath = resolveEntityPath(controllerName, moduleKey);
|
||||
String menuName = resolveMenuName(controllerClass, entityPath);
|
||||
|
||||
BaseSysMenuEntity pageMenu = new BaseSysMenuEntity();
|
||||
pageMenu.setName(menuName);
|
||||
pageMenu.setType(1);
|
||||
pageMenu.setRouter("/" + moduleKey + "/" + entityPath);
|
||||
pageMenu.setViewPath(moduleKey + "/" + entityPath + "/list.vue");
|
||||
pageMenu.setParentId(dirMenu.getId());
|
||||
pageMenu.setOrderNum(0);
|
||||
pageMenu.setKeepAlive(true);
|
||||
pageMenu.setIsShow(true);
|
||||
baseSysMenuMapper.insertSelective(pageMenu);
|
||||
|
||||
menuIds.add(pageMenu.getId());
|
||||
}
|
||||
|
||||
module.setMenuIds(new cn.hutool.json.JSONArray(menuIds).toString());
|
||||
this.update(module);
|
||||
|
||||
baseSysPermsService.refreshPermsByMenuId(null);
|
||||
|
||||
log.info("[AppModuleService] 模块 {} 自动创建菜单完成,menuIds={}", moduleKey, menuIds);
|
||||
}
|
||||
|
||||
private String resolveEntityPath(String controllerName, String moduleKey) {
|
||||
String name = controllerName;
|
||||
if (name.startsWith("Admin")) {
|
||||
name = name.substring(5);
|
||||
}
|
||||
if (name.endsWith("Controller")) {
|
||||
name = name.substring(0, name.length() - 10);
|
||||
}
|
||||
|
||||
String modulePrefix = StrUtil.upperFirst(moduleKey);
|
||||
if (name.startsWith(modulePrefix)) {
|
||||
name = name.substring(modulePrefix.length());
|
||||
}
|
||||
|
||||
return StrUtil.toCamelCase(name).toLowerCase();
|
||||
}
|
||||
|
||||
private String resolveMenuName(Class<?> controllerClass, String entityPath) {
|
||||
io.swagger.v3.oas.annotations.tags.Tag tag =
|
||||
AnnotatedElementUtils.findMergedAnnotation(controllerClass, io.swagger.v3.oas.annotations.tags.Tag.class);
|
||||
if (tag != null && StrUtil.isNotBlank(tag.name())) {
|
||||
return tag.name();
|
||||
}
|
||||
|
||||
try {
|
||||
java.lang.reflect.ParameterizedType pt =
|
||||
(java.lang.reflect.ParameterizedType) controllerClass.getGenericSuperclass();
|
||||
Class<?> entityClass = (Class<?>) pt.getActualTypeArguments()[1];
|
||||
Table tableAnno = AnnotatedElementUtils.findMergedAnnotation(entityClass, Table.class);
|
||||
if (tableAnno != null && StrUtil.isNotBlank(tableAnno.comment())) {
|
||||
return tableAnno.comment().replace("表", "");
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
return entityPath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,14 +150,22 @@ public class AppOrgServiceImpl extends BaseServiceImpl<AppOrgMapper, AppOrgEntit
|
||||
@Override
|
||||
public Dict switchOrg(Long userId, Long orgId, boolean isAdmin) {
|
||||
if (isAdmin) {
|
||||
BaseSysUserRoleEntity userRole = baseSysUserRoleMapper.selectOneByQuery(
|
||||
QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userId)
|
||||
);
|
||||
CoolPreconditions.checkEmpty(userRole, "无权切换到该组织");
|
||||
|
||||
BaseSysRoleEntity role = baseSysRoleMapper.selectOneById(userRole.getRoleId());
|
||||
CoolPreconditions.checkEmpty(role, "角色不存在");
|
||||
CoolPreconditions.check(!orgId.equals(role.getTenantId()), "无权切换到该组织");
|
||||
if (com.cool.core.util.CoolSecurityUtil.isSuperAdmin()) {
|
||||
// 超管可切换到任意组织
|
||||
} else {
|
||||
List<BaseSysUserRoleEntity> userRoles = baseSysUserRoleMapper.selectListByQuery(
|
||||
QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userId)
|
||||
);
|
||||
boolean hasAccess = false;
|
||||
for (BaseSysUserRoleEntity ur : userRoles) {
|
||||
BaseSysRoleEntity role = baseSysRoleMapper.selectOneById(ur.getRoleId());
|
||||
if (role != null && orgId.equals(role.getTenantId())) {
|
||||
hasAccess = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CoolPreconditions.check(!hasAccess, "无权切换到该组织");
|
||||
}
|
||||
} else {
|
||||
CoolPreconditions.check(!appOrgUserService.isOrgMember(userId, orgId), "未加入该组织");
|
||||
}
|
||||
@@ -166,18 +174,29 @@ public class AppOrgServiceImpl extends BaseServiceImpl<AppOrgMapper, AppOrgEntit
|
||||
CoolPreconditions.checkEmpty(org, "组织不存在");
|
||||
CoolPreconditions.check(org.getStatus() == 0, "组织已停用");
|
||||
|
||||
if (!isAdmin) {
|
||||
if (isAdmin) {
|
||||
com.cool.modules.base.entity.sys.BaseSysUserEntity adminUser = baseSysUserMapper.selectOneById(userId);
|
||||
CoolPreconditions.checkEmpty(adminUser, "用户不存在");
|
||||
|
||||
Dict tokenInfo = Dict.create()
|
||||
.set("userType", UserTypeEnum.APP.name())
|
||||
.set("userType", UserTypeEnum.ADMIN.name())
|
||||
.set("userId", userId)
|
||||
.set("orgId", orgId);
|
||||
.set("username", adminUser.getUsername())
|
||||
.set("tenantId", orgId);
|
||||
String token = jwtTokenUtil.generateToken(tokenInfo);
|
||||
String refreshToken = jwtTokenUtil.generateRefreshToken(tokenInfo);
|
||||
|
||||
JwtUser jwtUser = new JwtUser(userId,
|
||||
List.of(new SimpleGrantedAuthority("ROLE_" + UserTypeEnum.APP.name())),
|
||||
Long[] roleIds = baseSysPermsService.getRoles(userId);
|
||||
List<org.springframework.security.core.GrantedAuthority> authorities = new java.util.ArrayList<>();
|
||||
if (roleIds != null) {
|
||||
for (Long rid : roleIds) {
|
||||
authorities.add(new SimpleGrantedAuthority("ROLE_" + rid));
|
||||
}
|
||||
}
|
||||
JwtUser jwtUser = new JwtUser(userId, adminUser.getUsername(), adminUser.getPassword(),
|
||||
authorities,
|
||||
true);
|
||||
coolCache.set("app:userDetails:" + userId, jwtUser);
|
||||
coolCache.set("admin:userDetails:" + adminUser.getUsername(), jwtUser);
|
||||
|
||||
return Dict.create()
|
||||
.set("token", token)
|
||||
@@ -186,7 +205,52 @@ public class AppOrgServiceImpl extends BaseServiceImpl<AppOrgMapper, AppOrgEntit
|
||||
.set("refreshExpire", jwtTokenUtil.getRefreshExpire())
|
||||
.set("orgId", orgId);
|
||||
}
|
||||
return Dict.create().set("orgId", orgId);
|
||||
|
||||
Dict tokenInfo = Dict.create()
|
||||
.set("userType", UserTypeEnum.APP.name())
|
||||
.set("userId", userId)
|
||||
.set("orgId", orgId);
|
||||
String token = jwtTokenUtil.generateToken(tokenInfo);
|
||||
String refreshToken = jwtTokenUtil.generateRefreshToken(tokenInfo);
|
||||
|
||||
JwtUser jwtUser = new JwtUser(userId,
|
||||
List.of(new SimpleGrantedAuthority("ROLE_" + UserTypeEnum.APP.name())),
|
||||
true);
|
||||
coolCache.set("app:userDetails:" + userId, jwtUser);
|
||||
|
||||
return Dict.create()
|
||||
.set("token", token)
|
||||
.set("expire", jwtTokenUtil.getExpire())
|
||||
.set("refreshToken", refreshToken)
|
||||
.set("refreshExpire", jwtTokenUtil.getRefreshExpire())
|
||||
.set("orgId", orgId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AppOrgEntity> listForSwitch(Long userId) {
|
||||
if (com.cool.core.util.CoolSecurityUtil.isSuperAdmin()) {
|
||||
return this.list(QueryWrapper.create()
|
||||
.eq(AppOrgEntity::getStatus, 1)
|
||||
.orderBy(AppOrgEntity::getId, true));
|
||||
}
|
||||
|
||||
List<BaseSysUserRoleEntity> userRoles = baseSysUserRoleMapper.selectListByQuery(
|
||||
QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userId)
|
||||
);
|
||||
List<Long> orgIds = new java.util.ArrayList<>();
|
||||
for (BaseSysUserRoleEntity ur : userRoles) {
|
||||
BaseSysRoleEntity role = baseSysRoleMapper.selectOneById(ur.getRoleId());
|
||||
if (role != null && role.getTenantId() != null && role.getStatus() != 0) {
|
||||
orgIds.add(role.getTenantId());
|
||||
}
|
||||
}
|
||||
if (orgIds.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
return this.list(QueryWrapper.create()
|
||||
.in(AppOrgEntity::getId, orgIds)
|
||||
.eq(AppOrgEntity::getStatus, 1)
|
||||
.orderBy(AppOrgEntity::getId, true));
|
||||
}
|
||||
|
||||
private String generateInviteCode() {
|
||||
|
||||
Reference in New Issue
Block a user