diff --git a/server/REST API/认证授权2API.http b/server/REST API/认证授权2API.http index f10005b..09caea4 100644 --- a/server/REST API/认证授权2API.http +++ b/server/REST API/认证授权2API.http @@ -1,11 +1,11 @@ ## 安全认证 ### 获取验证码 -### http://localhost:18891/auth/captcha/codes?codeKey=5jXzuwcoUzbtnHNh -GET {{baseUrl}}/auth/captcha/codes?codeKey=applezrgegbtnHNrefh +### http://localhost:18891/auth/captcha/codes?codeKey=sNHnDNSliZe7ynOLem +GET {{baseUrl}}/auth/captcha/codes?codeKey=sNHnDNSliZe7ynOLem -### [master]密码模式登录 +### [google]密码模式登录 POST {{baseUrl}}/auth/login Content-Type: application/json x-tenant-id: google @@ -14,8 +14,8 @@ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Fi { "username": "cb44dedf9846", "password": "123456", - "codeKey": "applezrgegbtnHNrefh", - "codeText": "dxfu" + "codeKey": "sNHnDNSliZe7ynOLem", + "codeText": "8mp8" } > {% @@ -28,6 +28,7 @@ client.global.set("refreshToken", response.body.data.refresh_token); POST {{baseUrl}}/auth/logout Content-Type: application/json x-tenant-id: google +x-project-id: 10003 Authorization: Bearer {{tokenValue}} @@ -42,6 +43,7 @@ Authorization: Bearer {{tokenValue}} GET {{baseUrl}}/auth/login/user Content-Type: application/json x-tenant-id: google +x-project-id: 10001 Authorization: Bearer {{tokenValue}} @@ -50,5 +52,6 @@ Authorization: Bearer {{tokenValue}} GET {{baseUrl}}/cms/project/simple/query?pageIndex=1&pageSize=5&keywords= Content-Type: application/json x-tenant-id: google +x-project-id: 10002 Authorization: Bearer {{tokenValue}} diff --git a/server/REST API/认证授权API.http b/server/REST API/认证授权API.http index 2a5ecd7..7ee72c1 100644 --- a/server/REST API/认证授权API.http +++ b/server/REST API/认证授权API.http @@ -16,7 +16,7 @@ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Fi "username": "admin", "password": "123456", "codeKey": "5jXzuwcoUzbtnHNh", - "codeText": "yjvm" + "codeText": "jxcd" } > {% diff --git a/server/internal-api/src/main/java/com/xaaef/molly/internal/api/ApiCmsProjectService.java b/server/internal-api/src/main/java/com/xaaef/molly/internal/api/ApiCmsProjectService.java index c2e09ae..59d1937 100644 --- a/server/internal-api/src/main/java/com/xaaef/molly/internal/api/ApiCmsProjectService.java +++ b/server/internal-api/src/main/java/com/xaaef/molly/internal/api/ApiCmsProjectService.java @@ -3,6 +3,8 @@ package com.xaaef.molly.internal.api; import com.xaaef.molly.internal.dto.CmsProjectDTO; import com.xaaef.molly.internal.dto.SysTenantDTO; +import java.util.Set; + /** *

@@ -42,4 +44,14 @@ public interface ApiCmsProjectService { */ long countProjectByDeptId(Long deptId); + + /** + * 根据 部门ID 获取 关联的 项目列表 + * + * @author WangChenChen + * @date 2023/8/11 10:47 + */ + Set listProjectByDeptId(Long deptId); + + } diff --git a/server/internal-api/src/main/java/com/xaaef/molly/internal/api/ApiSysTenantService.java b/server/internal-api/src/main/java/com/xaaef/molly/internal/api/ApiSysTenantService.java index 48eb2f6..9be4a2e 100644 --- a/server/internal-api/src/main/java/com/xaaef/molly/internal/api/ApiSysTenantService.java +++ b/server/internal-api/src/main/java/com/xaaef/molly/internal/api/ApiSysTenantService.java @@ -1,5 +1,6 @@ package com.xaaef.molly.internal.api; +import com.xaaef.molly.internal.dto.MultiTenantPropertiesDTO; import com.xaaef.molly.internal.dto.SysTenantDTO; /** @@ -14,6 +15,15 @@ import com.xaaef.molly.internal.dto.SysTenantDTO; public interface ApiSysTenantService { + /** + * 判断 租户ID 是否存在 + * + * @author WangChenChen + * @date 2023/2/14 10:53 + */ + boolean existById(String tenantId); + + /** * 根据租户ID 获取租户信息 * @@ -49,4 +59,13 @@ public interface ApiSysTenantService { String getByDefaultTenantId(); + /** + * 获取 多租户配置 + * + * @author WangChenChen + * @date 2023/2/14 10:53 + */ + MultiTenantPropertiesDTO getByMultiTenantProperties(); + + } diff --git a/server/internal-api/src/main/java/com/xaaef/molly/internal/dto/CmsProjectDTO.java b/server/internal-api/src/main/java/com/xaaef/molly/internal/dto/CmsProjectDTO.java index dda640d..219c79e 100644 --- a/server/internal-api/src/main/java/com/xaaef/molly/internal/dto/CmsProjectDTO.java +++ b/server/internal-api/src/main/java/com/xaaef/molly/internal/dto/CmsProjectDTO.java @@ -15,6 +15,7 @@ import lombok.experimental.Accessors; * @date 2021/7/5 9:31 */ + @Schema(description = "项目") @Getter @Setter @@ -49,7 +50,13 @@ public class CmsProjectDTO implements java.io.Serializable { private String contactNumber; /** - * 联系地址 + * 行政地址 + */ + @Schema(description = "行政地址") + private Long areaCode; + + /** + * 联系地址 如:左右云创谷1栋A座 */ @Schema(description = "联系地址") private String address; @@ -72,4 +79,10 @@ public class CmsProjectDTO implements java.io.Serializable { @Schema(description = "状态 【0.禁用 1.正常 2.锁定 】") private Byte status; + /** + * 所属部门 + */ + @Schema(description = "所属部门Id") + private Long deptId; + } diff --git a/server/internal-api/src/main/java/com/xaaef/molly/internal/dto/MultiTenantPropertiesDTO.java b/server/internal-api/src/main/java/com/xaaef/molly/internal/dto/MultiTenantPropertiesDTO.java new file mode 100644 index 0000000..55a5bd5 --- /dev/null +++ b/server/internal-api/src/main/java/com/xaaef/molly/internal/dto/MultiTenantPropertiesDTO.java @@ -0,0 +1,50 @@ +package com.xaaef.molly.internal.dto; + +import lombok.Getter; +import lombok.Setter; + +/** + *

+ * 多租户全局配置 + *

+ * + * @author WangChenChen + * @version 1.1 + * @date 2022/12/9 11:53 + */ + +@Getter +@Setter +public class MultiTenantPropertiesDTO { + + /** + * 是否开启租户模式 + */ + private Boolean enable; + + /** + * 是否开启租户模式 + */ + private Boolean enableProject; + + /** + * 数据库名称前缀 + */ + private String prefix; + + /** + * 默认租户ID + */ + private String defaultTenantId; + + /** + * 默认 项目ID + */ + private Long defaultProjectId; + + /** + * 默认 数据库名称 + */ + private String dbName; + +} diff --git a/server/molly-cms/src/main/java/com/xaaef/molly/corems/api/impl/ApiCmsProjectServiceImpl.java b/server/molly-cms/src/main/java/com/xaaef/molly/corems/api/impl/ApiCmsProjectServiceImpl.java index 0b5b871..69811de 100644 --- a/server/molly-cms/src/main/java/com/xaaef/molly/corems/api/impl/ApiCmsProjectServiceImpl.java +++ b/server/molly-cms/src/main/java/com/xaaef/molly/corems/api/impl/ApiCmsProjectServiceImpl.java @@ -5,16 +5,21 @@ import com.xaaef.molly.common.enums.StatusEnum; import com.xaaef.molly.corems.entity.CmsProject; import com.xaaef.molly.corems.mapper.CmsProjectMapper; import com.xaaef.molly.internal.api.ApiCmsProjectService; +import com.xaaef.molly.internal.api.ApiPmsDeptService; import com.xaaef.molly.internal.api.ApiSysConfigService; import com.xaaef.molly.internal.dto.CmsProjectDTO; import com.xaaef.molly.internal.dto.SysTenantDTO; -import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import static com.xaaef.molly.auth.jwt.JwtSecurityUtils.encryptPassword; import static com.xaaef.molly.common.consts.ConfigName.USER_DEFAULT_PASSWORD; @@ -32,30 +37,41 @@ import static com.xaaef.molly.tenant.util.DelegateUtils.delegate; @Slf4j @Service -@AllArgsConstructor public class ApiCmsProjectServiceImpl implements ApiCmsProjectService { + @Autowired + @Lazy + private ApiPmsDeptService pmsDeptService; + private final CmsProjectMapper projectMapper; private final ApiSysConfigService configService; + public ApiCmsProjectServiceImpl(CmsProjectMapper projectMapper, + ApiSysConfigService configService) { + this.projectMapper = projectMapper; + this.configService = configService; + } + @Override public CmsProjectDTO getSimpleById(Long projectId) { var wrapper = new LambdaQueryWrapper() - .select(List.of(CmsProject::getProjectId, CmsProject::getProjectName, - CmsProject::getLinkman, CmsProject::getContactNumber)) + .select( + List.of( + CmsProject::getProjectId, CmsProject::getProjectName, + CmsProject::getLinkman, CmsProject::getAreaCode, CmsProject::getAddress + ) + ) .eq(CmsProject::getStatus, StatusEnum.NORMAL.getCode()) .eq(CmsProject::getProjectId, projectId); var source = projectMapper.selectOne(wrapper); if (source == null) { return null; } - return new CmsProjectDTO() - .setProjectId(source.getProjectId()) - .setProjectName(source.getProjectName()) - .setLinkman(source.getLinkman()) - .setContactNumber(source.getContactNumber()); + var target = new CmsProjectDTO(); + BeanUtils.copyProperties(source, target); + return target; } @@ -90,4 +106,17 @@ public class ApiCmsProjectServiceImpl implements ApiCmsProjectService { } + @Override + public Set listProjectByDeptId(Long deptId) { + var deptIds = pmsDeptService.listChildIdByDeptId(deptId); + var wrapper = new LambdaQueryWrapper() + .select(CmsProject::getProjectId) + .in(CmsProject::getDeptId, deptIds); + return projectMapper.selectList(wrapper) + .stream() + .map(CmsProject::getProjectId) + .collect(Collectors.toSet()); + } + + } diff --git a/server/molly-pms/src/main/java/com/xaaef/molly/perms/controller/PmsUserController.java b/server/molly-pms/src/main/java/com/xaaef/molly/perms/controller/PmsUserController.java index ee73bce..4106dbe 100644 --- a/server/molly-pms/src/main/java/com/xaaef/molly/perms/controller/PmsUserController.java +++ b/server/molly-pms/src/main/java/com/xaaef/molly/perms/controller/PmsUserController.java @@ -3,6 +3,7 @@ package com.xaaef.molly.perms.controller; import com.baomidou.mybatisplus.core.metadata.IPage; import com.xaaef.molly.auth.jwt.JwtLoginUser; import com.xaaef.molly.auth.jwt.JwtSecurityUtils; +import com.xaaef.molly.auth.service.JwtTokenService; import com.xaaef.molly.common.domain.Pagination; import com.xaaef.molly.common.util.JsonResult; import com.xaaef.molly.perms.entity.PmsUser; @@ -21,8 +22,8 @@ import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.Collection; import java.util.List; -import java.util.Set; import static com.xaaef.molly.tenant.util.DelegateUtils.delegate; @@ -45,6 +46,8 @@ public class PmsUserController { private final PmsUserService baseService; + private final JwtTokenService jwtTokenService; + @Operation(summary = "用户权限", description = "用户权限") @GetMapping("/rights") @@ -65,8 +68,8 @@ public class PmsUserController { @Operation(summary = "在线用户查询", description = "在线用户 查询所有") @GetMapping("/online/query") - public JsonResult> pageQuery2() { - return JsonResult.success(baseService.listLoginUsers()); + public JsonResult> pageQuery2() { + return JsonResult.success(jwtTokenService.mapLoginUser().values()); } diff --git a/server/molly-pms/src/main/java/com/xaaef/molly/perms/service/PmsUserService.java b/server/molly-pms/src/main/java/com/xaaef/molly/perms/service/PmsUserService.java index 67238e4..e50db14 100644 --- a/server/molly-pms/src/main/java/com/xaaef/molly/perms/service/PmsUserService.java +++ b/server/molly-pms/src/main/java/com/xaaef/molly/perms/service/PmsUserService.java @@ -1,6 +1,5 @@ package com.xaaef.molly.perms.service; -import com.xaaef.molly.auth.jwt.JwtLoginUser; import com.xaaef.molly.perms.entity.PmsUser; import com.xaaef.molly.perms.vo.ResetPasswordVO; import com.xaaef.molly.perms.vo.UpdatePasswordVO; @@ -21,15 +20,6 @@ import java.util.Set; public interface PmsUserService extends BaseService { - /** - * TODO 在线的所有用户 - * - * @author WangChenChen - * @date 2023/4/22 8:50 - */ - Set listLoginUsers(); - - /** * 修改密码 * diff --git a/server/molly-pms/src/main/java/com/xaaef/molly/perms/service/impl/PmsUserServiceImpl.java b/server/molly-pms/src/main/java/com/xaaef/molly/perms/service/impl/PmsUserServiceImpl.java index 7461d90..6dd8ef0 100644 --- a/server/molly-pms/src/main/java/com/xaaef/molly/perms/service/impl/PmsUserServiceImpl.java +++ b/server/molly-pms/src/main/java/com/xaaef/molly/perms/service/impl/PmsUserServiceImpl.java @@ -2,19 +2,20 @@ package com.xaaef.molly.perms.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.copier.CopyOptions; -import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.tree.TreeNode; import cn.hutool.core.lang.tree.TreeUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.support.SFunction; -import com.xaaef.molly.auth.jwt.JwtLoginUser; import com.xaaef.molly.auth.jwt.JwtSecurityUtils; import com.xaaef.molly.auth.service.JwtTokenService; +import com.xaaef.molly.auth.service.UserLoginService; import com.xaaef.molly.common.enums.AdminFlag; import com.xaaef.molly.common.enums.StatusEnum; +import com.xaaef.molly.common.enums.UserType; import com.xaaef.molly.common.po.SearchPO; import com.xaaef.molly.common.util.IdUtils; +import com.xaaef.molly.internal.api.ApiCmsProjectService; import com.xaaef.molly.internal.api.ApiSysConfigService; import com.xaaef.molly.internal.api.ApiSysMenuService; import com.xaaef.molly.internal.dto.PmsRoleDTO; @@ -64,8 +65,12 @@ public class PmsUserServiceImpl extends BaseServiceImpl private final ApiSysConfigService configService; + private final ApiCmsProjectService cmsProjectService; + private final ApiSysMenuService menuService; + private final UserLoginService userLoginService; + private final PmsRoleService roleService; private final PmsDeptService deptService; @@ -74,6 +79,7 @@ public class PmsUserServiceImpl extends BaseServiceImpl private final JwtTokenService jwtTokenService; + @Override public IPage pageKeywords(SearchPO params, Collection> columns) { var result = super.pageKeywords(params, columns); @@ -87,13 +93,14 @@ public class PmsUserServiceImpl extends BaseServiceImpl var deptIds = list.stream().map(PmsUser::getDeptId).collect(Collectors.toSet()); var roleMaps = roleService.listByUserIds(userIds); var deptMaps = deptService.listByIds(deptIds).stream().collect(Collectors.toMap(PmsDept::getDeptId, d -> d)); - var online = jwtTokenService.listUsernames(); + var loginUserMap = jwtTokenService.mapLoginUser(); list.forEach(r -> { r.setPassword(null); r.setRoles(roleMaps.get(r.getUserId())); r.setDept(deptMaps.get(r.getDeptId())); // 如果包含,那么就是在线。【 0.离线 1.在线】 - r.setLoginFlag(CollectionUtil.contains(online, r.getUsername()) ? (byte) 1 : (byte) 0); + var loginFlag = loginUserMap.containsKey(r.getUserId()) ? (byte) 1 : (byte) 0; + r.setLoginFlag(loginFlag); }); } } @@ -194,7 +201,14 @@ public class PmsUserServiceImpl extends BaseServiceImpl var copyOptions = CopyOptions.create(); copyOptions.setIgnoreNullValue(true); BeanUtil.copyProperties(entity, loginUser, copyOptions); - jwtTokenService.updateLoginUser(loginUser); + // 非管理员 用户。根据部门Id获取关联的项目Id + if (loginUser.getUserType() == UserType.TENANT + && Objects.equals(entity.getAdminFlag(), AdminFlag.NO.getCode())) { + // 获取当前登录的用户 项目ID 列表 + var haveProjectIds = cmsProjectService.listProjectByDeptId(entity.getDeptId()); + loginUser.setHaveProjectIds(haveProjectIds); + } + userLoginService.refreshAuthoritys(loginUser); } return super.updateById(entity); } @@ -280,17 +294,6 @@ public class PmsUserServiceImpl extends BaseServiceImpl } - @Override - public Set listLoginUsers() { - return jwtTokenService.listLoginUsers() - .stream() - .peek(r -> { - r.setPassword(null); - r.setAuthorities(null); - }).collect(Collectors.toSet()); - } - - @Transactional(rollbackFor = Exception.class) @Override public boolean updatePassword(UpdatePasswordVO pwd) { diff --git a/server/molly-service/src/main/resources/application-dev.yml b/server/molly-service/src/main/resources/application-dev.yml index d6fccc6..d37be1f 100644 --- a/server/molly-service/src/main/resources/application-dev.yml +++ b/server/molly-service/src/main/resources/application-dev.yml @@ -2,7 +2,7 @@ spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.0.188:3306/${multi.tenant.db-name:molly_master}?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true - username: root + username: test123 password: mht123456 type: com.zaxxer.hikari.HikariDataSource @@ -10,7 +10,7 @@ spring: data: redis: host: 192.168.0.188 - database: 6 + database: 7 port: 6379 timeout: 5000 lettuce: diff --git a/server/molly-sys/src/main/java/com/xaaef/molly/system/api/impl/ApiSysTenantServiceImpl.java b/server/molly-sys/src/main/java/com/xaaef/molly/system/api/impl/ApiSysTenantServiceImpl.java index 378a1e8..e9b8efa 100644 --- a/server/molly-sys/src/main/java/com/xaaef/molly/system/api/impl/ApiSysTenantServiceImpl.java +++ b/server/molly-sys/src/main/java/com/xaaef/molly/system/api/impl/ApiSysTenantServiceImpl.java @@ -3,9 +3,11 @@ package com.xaaef.molly.system.api.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.xaaef.molly.common.util.TenantUtils; import com.xaaef.molly.internal.api.ApiSysTenantService; +import com.xaaef.molly.internal.dto.MultiTenantPropertiesDTO; import com.xaaef.molly.internal.dto.SysTenantDTO; import com.xaaef.molly.system.entity.SysTenant; import com.xaaef.molly.system.mapper.SysTenantMapper; +import com.xaaef.molly.tenant.props.MultiTenantProperties; import com.xaaef.molly.tenant.service.MultiTenantManager; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -31,6 +33,14 @@ public class ApiSysTenantServiceImpl implements ApiSysTenantService { private final MultiTenantManager tenantManager; + private final MultiTenantProperties multiTenantProperties; + + @Override + public boolean existById(String tenantId) { + return tenantManager.existById(tenantId); + } + + @Override public SysTenantDTO getByTenantId(String tenantId) { var source = tenantMapper.selectById(tenantId); @@ -70,7 +80,15 @@ public class ApiSysTenantServiceImpl implements ApiSysTenantService { @Override public String getByDefaultTenantId() { - return tenantManager.getDefaultTenantId(); + return multiTenantProperties.getDefaultTenantId(); + } + + + @Override + public MultiTenantPropertiesDTO getByMultiTenantProperties() { + var target = new MultiTenantPropertiesDTO(); + BeanUtils.copyProperties(multiTenantProperties, target); + return target; } diff --git a/server/molly-sys/src/main/java/com/xaaef/molly/system/cron/TestCronAsync.java b/server/molly-sys/src/main/java/com/xaaef/molly/system/cron/TestCronAsync.java index cdf5128..243a886 100644 --- a/server/molly-sys/src/main/java/com/xaaef/molly/system/cron/TestCronAsync.java +++ b/server/molly-sys/src/main/java/com/xaaef/molly/system/cron/TestCronAsync.java @@ -70,7 +70,7 @@ public class TestCronAsync { @Scheduled(fixedRate = 60000) public void cron2() { var ind = count2.decrementAndGet(); - tokenService.listLoginUsers().forEach(user -> { + tokenService.mapAllLoginUser().forEach((userId, user) -> { var map = Map.of( "id", IdUtils.getStandaloneId(), "title", String.format("推送消息=>%d", RandomUtil.randomInt(10000, 99999)), diff --git a/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/controller/AuthController.java b/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/controller/AuthController.java index 829bca1..48e8c6b 100644 --- a/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/controller/AuthController.java +++ b/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/controller/AuthController.java @@ -100,7 +100,7 @@ public class AuthController { try { var tokenValue = loginService.login(user, request); return JsonResult.success("登录成功", tokenValue); - } catch (Exception failed) { + } catch (RuntimeException failed) { String msg = null; if (failed instanceof UsernameNotFoundException) { msg = StrUtil.format("用户名 {} 不存在", user.getUsername()); diff --git a/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/enums/OAuth2Error.java b/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/enums/OAuth2Error.java index b8057cc..77ba08e 100644 --- a/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/enums/OAuth2Error.java +++ b/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/enums/OAuth2Error.java @@ -157,7 +157,7 @@ public enum OAuth2Error { /** * 此系统用户不包含 此项目ID */ - NO_HAVE_PROJECT_PERMISSIONS(400447, "此用户不包含此项目ID"); + NO_HAVE_PROJECT_PERMISSIONS(400447, "用户没有操作此项目的权限"); OAuth2Error(Integer status, String error) { diff --git a/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/JwtTokenService.java b/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/JwtTokenService.java index 8287543..f5c0723 100644 --- a/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/JwtTokenService.java +++ b/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/JwtTokenService.java @@ -5,6 +5,7 @@ import com.xaaef.molly.auth.jwt.JwtLoginUser; import com.xaaef.molly.auth.jwt.JwtTokenProperties; import com.xaaef.molly.auth.jwt.JwtTokenValue; +import java.util.Map; import java.util.Set; @@ -88,13 +89,13 @@ public interface JwtTokenService { /** - * 获取 所有的在线的用户名 + * 获取 当前租户,在线的用户信息 * * @return String 用户名称 * @author Wang Chen Chen * @date 2021/7/12 16:29 */ - Set listUsernames(); + Set listLoginUsername(); /** @@ -108,13 +109,27 @@ public interface JwtTokenService { /** - * 获取 所有的在线的用户信息 + * 获取 当前租户,在线的 用户信息 + * key: 用户ID + * value: 用户信息 * * @return String 用户名称 * @author Wang Chen Chen * @date 2021/7/12 16:29 */ - Set listLoginUsers(); + Map mapLoginUser(); + + + /** + * 获取 所有租户 在线的 用户信息 + * key: 用户ID + * value: 用户信息 + * + * @return String 用户名称 + * @author Wang Chen Chen + * @date 2021/7/12 16:29 + */ + Map mapAllLoginUser(); /** diff --git a/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/UserLoginService.java b/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/UserLoginService.java index fc80fa7..b1ea170 100644 --- a/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/UserLoginService.java +++ b/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/UserLoginService.java @@ -1,6 +1,7 @@ package com.xaaef.molly.auth.service; import com.xaaef.molly.auth.exception.JwtAuthException; +import com.xaaef.molly.auth.jwt.JwtLoginUser; import com.xaaef.molly.auth.jwt.JwtTokenValue; import com.xaaef.molly.auth.po.LoginFormPO; import jakarta.servlet.http.HttpServletRequest; @@ -37,4 +38,10 @@ public interface UserLoginService { void refreshAuthoritys(); + /** + * 刷新内存中用户的权限 + */ + void refreshAuthoritys(JwtLoginUser loginUser); + + } diff --git a/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/impl/JwtTokenServiceImpl.java b/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/impl/JwtTokenServiceImpl.java index 95b70ce..dc375f6 100644 --- a/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/impl/JwtTokenServiceImpl.java +++ b/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/impl/JwtTokenServiceImpl.java @@ -21,6 +21,8 @@ import org.springframework.security.core.context.SecurityContextHolder; import java.time.Duration; import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -223,7 +225,7 @@ public class JwtTokenServiceImpl implements JwtTokenService { @Override - public Set listUsernames() { + public Set listLoginUsername() { var onlineUserKey = ONLINE_USER_KEY + "*"; return Objects.requireNonNull(strRedisTemplate.keys(onlineUserKey)) .stream() @@ -243,11 +245,43 @@ public class JwtTokenServiceImpl implements JwtTokenService { @Override - public Set listLoginUsers() { - return this.listLoginIds() + public Map mapLoginUser() { + var onlineUserKey = ONLINE_USER_KEY + "*"; + var keys = strRedisTemplate.keys(onlineUserKey); + if (keys == null || keys.isEmpty()) { + return new HashMap<>(); + } + var loginIds = strRedisTemplate.opsForValue().multiGet(keys); + if (loginIds == null || loginIds.isEmpty()) { + return new HashMap<>(); + } + var loginUserKeys = loginIds .stream() - .map(this::getLoginUser) + .map(loginId -> LOGIN_TOKEN_KEY + loginId) .collect(Collectors.toSet()); + return mapLoginUser(loginUserKeys); + } + + + @Override + public Map mapAllLoginUser() { + var keys = strRedisTemplate.keys(LOGIN_TOKEN_KEY + "*"); + return mapLoginUser(keys); + } + + + private Map mapLoginUser(Set keys) { + var result = new HashMap(); + if (keys == null || keys.isEmpty()) { + return result; + } + var objects = redisTemplate.opsForValue().multiGet(keys); + if (objects == null || objects.isEmpty()) { + return result; + } + return objects.stream() + .map(a -> BeanUtil.copyProperties(a, JwtLoginUser.class)) + .collect(Collectors.toMap(JwtLoginUser::getUserId, a -> a)); } @@ -256,4 +290,5 @@ public class JwtTokenServiceImpl implements JwtTokenService { return props; } + } diff --git a/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/impl/UserLoginServiceImpl.java b/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/impl/UserLoginServiceImpl.java index 275e342..e2ff28a 100644 --- a/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/impl/UserLoginServiceImpl.java +++ b/server/plugins/auth-jwt/src/main/java/com/xaaef/molly/auth/service/impl/UserLoginServiceImpl.java @@ -31,6 +31,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.stereotype.Service; import java.time.LocalDateTime; +import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; @@ -70,6 +71,8 @@ public class UserLoginServiceImpl implements UserLoginService { private final ApiSysUserService sysUserService; + private final ApiCmsProjectService cmsProjectService; + /** * 登录表单获取 Token @@ -111,6 +114,8 @@ public class UserLoginServiceImpl implements UserLoginService { target.setGrantType(GrantType.PASSWORD); target.setLoginTime(LocalDateTime.now()); target.setTenantId(currentTenant.getTenantId()); + // 生成一个随机ID 跟当前用户关联 + target.setLoginId(IdUtil.simpleUUID()); // 判断当前登录的用户类型。系统用户 还是 租户用户 String defaultTenantId = tenantService.getByDefaultTenantId(); @@ -118,14 +123,20 @@ public class UserLoginServiceImpl implements UserLoginService { ? UserType.SYSTEM : UserType.TENANT; target.setUserType(userType); - // 生成一个随机ID 跟当前用户关联 - target.setLoginId(IdUtil.simpleUUID()); + target.setHaveProjectIds(new HashSet<>()); + target.setHaveTenantIds(new HashSet<>()); // 如果当前登录的用户,是否系统用户 if (userType == UserType.SYSTEM) { - target.setHaveTenantIds( - sysUserService.listHaveTenantIds(target.getUserId()) - ); + var haveTenantIds = sysUserService.listHaveTenantIds(target.getUserId()); + target.setHaveTenantIds(haveTenantIds); + } else { + // 非管理员 用户。根据部门Id获取关联的项目Id + if (target.getAdminFlag() == AdminFlag.NO) { + // 获取当前登录的用户 项目ID 列表 + var haveProjectIds = cmsProjectService.listProjectByDeptId(target.getDeptId()); + target.setHaveProjectIds(haveProjectIds); + } } // 设置角色和菜单权限 @@ -154,17 +165,21 @@ public class UserLoginServiceImpl implements UserLoginService { public void refreshAuthoritys() { // 判断用户是否登录 if (JwtSecurityUtils.isAuthenticated()) { - // 获取登录用户 - var target = JwtSecurityUtils.getLoginUser(); - target.setAuthorities(List.of()); - // 设置用户的权限 - setAuthoritys(target); - // 更新用户的权限 - tokenService.updateLoginUser(target); + refreshAuthoritys(JwtSecurityUtils.getLoginUser()); } } + @Override + public void refreshAuthoritys(JwtLoginUser target) { + target.setAuthorities(List.of()); + // 设置用户的权限 + setAuthoritys(target); + // 更新用户的权限 + tokenService.updateLoginUser(target); + } + + /** * 设置用户的权限 * diff --git a/server/plugins/web-config/pom.xml b/server/plugins/web-config/pom.xml index 7784934..6919bd6 100644 --- a/server/plugins/web-config/pom.xml +++ b/server/plugins/web-config/pom.xml @@ -36,7 +36,7 @@ com.xaaef.molly - mbp-tenant + auth-jwt ${project.version} diff --git a/server/plugins/web-config/src/main/java/com/xaaef/molly/web/CustomSpringWebConfig.java b/server/plugins/web-config/src/main/java/com/xaaef/molly/web/CustomSpringWebConfig.java index 0533c5f..b24ef43 100644 --- a/server/plugins/web-config/src/main/java/com/xaaef/molly/web/CustomSpringWebConfig.java +++ b/server/plugins/web-config/src/main/java/com/xaaef/molly/web/CustomSpringWebConfig.java @@ -4,9 +4,9 @@ import cn.hutool.core.net.Ipv4Util; import com.fasterxml.jackson.databind.ObjectMapper; import com.xaaef.molly.common.consts.JwtConst; import com.xaaef.molly.common.util.JsonUtils; -import com.xaaef.molly.tenant.ProjectIdInterceptor; -import com.xaaef.molly.tenant.TenantIdInterceptor; -import com.xaaef.molly.tenant.props.MultiTenantProperties; +import com.xaaef.molly.internal.api.ApiSysTenantService; +import com.xaaef.molly.web.interceptor.ProjectIdInterceptor; +import com.xaaef.molly.web.interceptor.TenantIdInterceptor; import com.xaaef.molly.web.repeat.NoRepeatSubmitInterceptor; import jakarta.annotation.PostConstruct; import lombok.AllArgsConstructor; @@ -66,7 +66,7 @@ public class CustomSpringWebConfig implements WebMvcConfigurer { // 获取项目ID 拦截器 private final ProjectIdInterceptor projectIdInterceptor; - private final MultiTenantProperties multiTenantProperties; + private final ApiSysTenantService tenantService; @Override @@ -76,6 +76,7 @@ public class CustomSpringWebConfig implements WebMvcConfigurer { .filter(s -> !JwtConst.LOGIN_URL.equals(s)) .collect(Collectors.toList()); + var multiTenantProperties = tenantService.getByMultiTenantProperties(); // 启用 租户ID 拦截器 if (multiTenantProperties.getEnable()) { registry.addInterceptor(tenantIdInterceptor) diff --git a/server/plugins/mbp-tenant/src/main/java/com/xaaef/molly/tenant/ProjectIdInterceptor.java b/server/plugins/web-config/src/main/java/com/xaaef/molly/web/interceptor/ProjectIdInterceptor.java similarity index 81% rename from server/plugins/mbp-tenant/src/main/java/com/xaaef/molly/tenant/ProjectIdInterceptor.java rename to server/plugins/web-config/src/main/java/com/xaaef/molly/web/interceptor/ProjectIdInterceptor.java index 7051149..38d1fdd 100644 --- a/server/plugins/mbp-tenant/src/main/java/com/xaaef/molly/tenant/ProjectIdInterceptor.java +++ b/server/plugins/web-config/src/main/java/com/xaaef/molly/web/interceptor/ProjectIdInterceptor.java @@ -1,4 +1,4 @@ -package com.xaaef.molly.tenant; +package com.xaaef.molly.web.interceptor; import cn.hutool.core.util.NumberUtil; @@ -8,8 +8,8 @@ import com.xaaef.molly.common.util.JsonResult; import com.xaaef.molly.common.util.ServletUtils; import com.xaaef.molly.common.util.TenantUtils; import com.xaaef.molly.internal.api.ApiCmsProjectService; +import com.xaaef.molly.internal.api.ApiSysTenantService; import com.xaaef.molly.internal.dto.CmsProjectDTO; -import com.xaaef.molly.tenant.props.MultiTenantProperties; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; @@ -38,7 +38,8 @@ public class ProjectIdInterceptor implements HandlerInterceptor { private final ApiCmsProjectService projectService; - private final MultiTenantProperties multiTenantProperties; + private final ApiSysTenantService tenantService; + @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { @@ -62,7 +63,12 @@ public class ProjectIdInterceptor implements HandlerInterceptor { TenantUtils.setProjectId(projectId); } else { // 使用 默认项目ID - TenantUtils.setProjectId(multiTenantProperties.getDefaultProjectId()); + var defaultProjectId = tenantService.getByMultiTenantProperties().getDefaultProjectId(); + TenantUtils.setProjectId(defaultProjectId); + } + // 校验 当前用户是否 有操作此项目的权限 + if (!haveProjectPermissions(response, TenantUtils.getProjectId())) { + return false; } return HandlerInterceptor.super.preHandle(request, response, handler); } @@ -72,8 +78,8 @@ public class ProjectIdInterceptor implements HandlerInterceptor { * 判断 当前用户是否拥有 此项目的 操作权限 */ private boolean haveProjectPermissions(HttpServletResponse response, Long projectId) { - // 如果当前用户是 系统用户 - if (JwtSecurityUtils.isMasterUser()) { + // 如果当前用户是 租户的非管理员用户。 + if (JwtSecurityUtils.isAuthenticated() && (!JwtSecurityUtils.isMasterUser() && !JwtSecurityUtils.isAdminUser())) { var haveProjectIds = JwtSecurityUtils.getLoginUser().getHaveProjectIds(); if (!haveProjectIds.isEmpty() && !haveProjectIds.contains(projectId)) { var err = StrUtil.format("您没有 项目ID {} 的操作权限!", projectId); diff --git a/server/plugins/mbp-tenant/src/main/java/com/xaaef/molly/tenant/TenantIdInterceptor.java b/server/plugins/web-config/src/main/java/com/xaaef/molly/web/interceptor/TenantIdInterceptor.java similarity index 94% rename from server/plugins/mbp-tenant/src/main/java/com/xaaef/molly/tenant/TenantIdInterceptor.java rename to server/plugins/web-config/src/main/java/com/xaaef/molly/web/interceptor/TenantIdInterceptor.java index 6e900e1..a94384c 100644 --- a/server/plugins/mbp-tenant/src/main/java/com/xaaef/molly/tenant/TenantIdInterceptor.java +++ b/server/plugins/web-config/src/main/java/com/xaaef/molly/web/interceptor/TenantIdInterceptor.java @@ -1,4 +1,4 @@ -package com.xaaef.molly.tenant; +package com.xaaef.molly.web.interceptor; import cn.hutool.core.util.StrUtil; @@ -8,7 +8,6 @@ import com.xaaef.molly.common.util.ServletUtils; import com.xaaef.molly.common.util.TenantUtils; import com.xaaef.molly.internal.api.ApiSysTenantService; import com.xaaef.molly.internal.dto.SysTenantDTO; -import com.xaaef.molly.tenant.service.MultiTenantManager; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; @@ -36,8 +35,6 @@ import static com.xaaef.molly.common.util.TenantUtils.X_TENANT_ID; @AllArgsConstructor public class TenantIdInterceptor implements HandlerInterceptor { - private final MultiTenantManager tenantManager; - private final ApiSysTenantService tenantService; @Override @@ -73,13 +70,13 @@ public class TenantIdInterceptor implements HandlerInterceptor { } } // 校验租户,是否存在系统中 - if (!tenantManager.existById(tenantId)) { + if (!tenantService.existById(tenantId)) { var err = StrUtil.format("租户ID {} 不存在!", tenantId); ServletUtils.renderError(response, JsonResult.result(TENANT_ID_DOES_NOT_EXIST.getStatus(), err)); return false; } TenantUtils.setTenantId(tenantId); - log.debug("preHandle.tenantId: {}", tenantId); + // 校验 当前用户是否 有操作此租户的权限 if (!haveTenantPermissions(response, tenantId)) { return false; } diff --git a/web-ui/src/views/pre/user/index.vue b/web-ui/src/views/pre/user/index.vue index f9d1179..64bbeef 100644 --- a/web-ui/src/views/pre/user/index.vue +++ b/web-ui/src/views/pre/user/index.vue @@ -59,13 +59,16 @@