1.更新,校验登录用户的项目权限!

2.添加 用户登录状态
This commit is contained in:
Wang Chen Chen
2023-11-06 18:18:56 +08:00
parent afd26142b6
commit 87695a215d
24 changed files with 309 additions and 90 deletions

View File

@@ -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}}

View File

@@ -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"
}
> {%

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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());
}
}

View File

@@ -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());
}

View File

@@ -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();
/**
* 修改密码
*

View File

@@ -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) {

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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)),

View File

@@ -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());

View File

@@ -157,7 +157,7 @@ public enum OAuth2Error {
/**
* 此系统用户不包含 此项目ID
*/
NO_HAVE_PROJECT_PERMISSIONS(400447, "用户不包含此项目ID");
NO_HAVE_PROJECT_PERMISSIONS(400447, "用户没有操作此项目的权限");
OAuth2Error(Integer status, String error) {

View File

@@ -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();
/**

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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);
}
/**
* 设置用户的权限
*

View File

@@ -36,7 +36,7 @@
<dependency>
<groupId>com.xaaef.molly</groupId>
<artifactId>mbp-tenant</artifactId>
<artifactId>auth-jwt</artifactId>
<version>${project.version}</version>
</dependency>

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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="过期时间">