mirror of
https://github.com/thousmile/molly-multi-tenant.git
synced 2025-12-30 12:42:26 +00:00
1.更新,校验登录用户的项目权限!
2.添加 用户登录状态
This commit is contained in:
@@ -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}}
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
> {%
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -42,4 +44,14 @@ public interface ApiCmsProjectService {
|
||||
*/
|
||||
long countProjectByDeptId(Long deptId);
|
||||
|
||||
|
||||
/**
|
||||
* 根据 部门ID 获取 关联的 项目列表
|
||||
*
|
||||
* @author WangChenChen
|
||||
* @date 2023/8/11 10:47
|
||||
*/
|
||||
Set<Long> listProjectByDeptId(Long deptId);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.xaaef.molly.internal.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 多租户全局配置
|
||||
* </p>
|
||||
*
|
||||
* @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;
|
||||
|
||||
}
|
||||
@@ -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<CmsProject>()
|
||||
.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<Long> listProjectByDeptId(Long deptId) {
|
||||
var deptIds = pmsDeptService.listChildIdByDeptId(deptId);
|
||||
var wrapper = new LambdaQueryWrapper<CmsProject>()
|
||||
.select(CmsProject::getProjectId)
|
||||
.in(CmsProject::getDeptId, deptIds);
|
||||
return projectMapper.selectList(wrapper)
|
||||
.stream()
|
||||
.map(CmsProject::getProjectId)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Set<JwtLoginUser>> pageQuery2() {
|
||||
return JsonResult.success(baseService.listLoginUsers());
|
||||
public JsonResult<Collection<JwtLoginUser>> pageQuery2() {
|
||||
return JsonResult.success(jwtTokenService.mapLoginUser().values());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<PmsUser> {
|
||||
|
||||
/**
|
||||
* TODO 在线的所有用户
|
||||
*
|
||||
* @author WangChenChen
|
||||
* @date 2023/4/22 8:50
|
||||
*/
|
||||
Set<JwtLoginUser> listLoginUsers();
|
||||
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*
|
||||
|
||||
@@ -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<PmsUserMapper, PmsUser>
|
||||
|
||||
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<PmsUserMapper, PmsUser>
|
||||
|
||||
private final JwtTokenService jwtTokenService;
|
||||
|
||||
|
||||
@Override
|
||||
public IPage<PmsUser> pageKeywords(SearchPO params, Collection<SFunction<PmsUser, ?>> columns) {
|
||||
var result = super.pageKeywords(params, columns);
|
||||
@@ -87,13 +93,14 @@ public class PmsUserServiceImpl extends BaseServiceImpl<PmsUserMapper, PmsUser>
|
||||
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<PmsUserMapper, PmsUser>
|
||||
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<PmsUserMapper, PmsUser>
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<JwtLoginUser> 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) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -157,7 +157,7 @@ public enum OAuth2Error {
|
||||
/**
|
||||
* 此系统用户不包含 此项目ID
|
||||
*/
|
||||
NO_HAVE_PROJECT_PERMISSIONS(400447, "此用户不包含此项目ID");
|
||||
NO_HAVE_PROJECT_PERMISSIONS(400447, "用户没有操作此项目的权限");
|
||||
|
||||
|
||||
OAuth2Error(Integer status, String error) {
|
||||
|
||||
@@ -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<String> listUsernames();
|
||||
Set<String> listLoginUsername();
|
||||
|
||||
|
||||
/**
|
||||
@@ -108,13 +109,27 @@ public interface JwtTokenService {
|
||||
|
||||
|
||||
/**
|
||||
* 获取 所有的在线的用户信息
|
||||
* 获取 当前租户,在线的 用户信息
|
||||
* key: 用户ID
|
||||
* value: 用户信息
|
||||
*
|
||||
* @return String 用户名称
|
||||
* @author Wang Chen Chen
|
||||
* @date 2021/7/12 16:29
|
||||
*/
|
||||
Set<JwtLoginUser> listLoginUsers();
|
||||
Map<Long, JwtLoginUser> mapLoginUser();
|
||||
|
||||
|
||||
/**
|
||||
* 获取 所有租户 在线的 用户信息
|
||||
* key: 用户ID
|
||||
* value: 用户信息
|
||||
*
|
||||
* @return String 用户名称
|
||||
* @author Wang Chen Chen
|
||||
* @date 2021/7/12 16:29
|
||||
*/
|
||||
Map<Long, JwtLoginUser> mapAllLoginUser();
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String> listUsernames() {
|
||||
public Set<String> 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<JwtLoginUser> listLoginUsers() {
|
||||
return this.listLoginIds()
|
||||
public Map<Long, JwtLoginUser> 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<Long, JwtLoginUser> mapAllLoginUser() {
|
||||
var keys = strRedisTemplate.keys(LOGIN_TOKEN_KEY + "*");
|
||||
return mapLoginUser(keys);
|
||||
}
|
||||
|
||||
|
||||
private Map<Long, JwtLoginUser> mapLoginUser(Set<String> keys) {
|
||||
var result = new HashMap<Long, JwtLoginUser>();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置用户的权限
|
||||
*
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>com.xaaef.molly</groupId>
|
||||
<artifactId>mbp-tenant</artifactId>
|
||||
<artifactId>auth-jwt</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -59,13 +59,16 @@
|
||||
</el-table-column>
|
||||
<el-table-column prop="adminFlag" label="管理员">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.adminFlag" type="success">是</el-tag>
|
||||
<el-tag v-if="scope.row.adminFlag">是</el-tag>
|
||||
<span v-else>否</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态">
|
||||
<template #default="scope">
|
||||
{{ dictStore.getNormalDisable(scope.row.status) }}
|
||||
<el-tag v-if="scope.row.loginFlag" type="success">在线</el-tag>
|
||||
<span v-else>
|
||||
{{ dictStore.getNormalDisable(scope.row.status) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="expired" label="过期时间">
|
||||
|
||||
Reference in New Issue
Block a user