Compare commits

...

62 Commits

Author SHA1 Message Date
65d737db6d Merge remote-tracking branch 'origin/springboot3_sas' into springboot3_sas 2024-08-21 15:22:11 +08:00
f04f7f9abf Merge pull request #6899 from EightMonth/springboot3_sas
缩短token长度,适配主分支前端页面登录
2024-08-21 15:14:01 +08:00
935e118d15 sas分支前端同步master分支 2024-08-21 12:46:58 +08:00
e218367332 登出及强退逻辑完善 2024-08-21 11:22:13 +08:00
3a3f3cf367 升级积木报表到v1.8.0 2024-08-20 16:41:14 +08:00
0e762b4157 缩短token长度,适配主分支前端页面登录 2024-07-15 17:11:05 +08:00
f4712baa39 Merge pull request #6879 from EightMonth/springboot3_sas
修复访问仪表盘401
2024-07-10 16:23:48 +08:00
7d8b653d6e 修复访问仪表盘401 2024-07-10 16:22:10 +08:00
cf7f3f94be Merge pull request #6878 from EightMonth/springboot3_sas
修复访问仪表盘401问题
2024-07-10 16:03:19 +08:00
49f63b92ac 修复访问仪表盘401问题 2024-07-10 16:01:57 +08:00
5670a15b20 Merge remote-tracking branch 'origin/springboot3' into springboot3_sas 2024-07-08 12:28:17 +08:00
9e9ef20b7c 改法不兼容,暂时先还原 2024-07-03 14:35:44 +08:00
0c034031d1 Merge branch 'springboot3_sas' of https://github.com/jeecgboot/jeecg-boot into springboot3_sas 2024-07-03 12:23:13 +08:00
491a038b5a 增加仪表盘的请求排除 2024-07-03 12:22:43 +08:00
8a4fcb0023 Merge remote-tracking branch 'origin/springboot3' into springboot3_sas 2024-07-03 12:02:32 +08:00
e93dcc1a7e Merge pull request #6660 from EightMonth/springboot3_sas
修复redis反序列化时间问题
2024-06-27 18:33:16 +08:00
383cbf250f 修复redis反序列化时间问题 2024-06-27 18:09:54 +08:00
9fe1450ac9 Merge pull request #6646 from EightMonth/springboot3_sas
sas实现免登录注解
2024-06-25 17:38:48 +08:00
88b9b12998 sas实现免登录注解 2024-06-25 17:32:57 +08:00
9e25566271 【重要更新】vue3前端为了适配springboot3 sas分支(Spring Authorization Server)特定修改 2024-06-23 11:25:55 +08:00
8e54e06978 Merge remote-tracking branch 'origin/springboot3' into springboot3_sas 2024-06-23 11:23:34 +08:00
e5c082ae13 版本合并前端和后端放到一起 2024-06-23 10:35:53 +08:00
96ab98ac3e Merge remote-tracking branch 'origin/springboot3' into springboot3_sas
# Conflicts:
#	jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgCaptchaException.java
#	jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/JwtToken.java
#	jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
#	jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java
#	jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/CustomShiroFilterFactoryBean.java
#	jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java
#	jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/ResourceCheckFilter.java
#	jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/Shiro.java
2024-06-23 10:29:34 +08:00
1632c241ee 修改nacos命名空间springboot3的id也是springboot3,方便理解 2024-06-22 23:23:55 +08:00
e9d05b0e75 访问积木报表提示token无权限,原因TokenUtils.getLoginUser方法报错 2024-06-22 22:59:34 +08:00
6ade7e22f8 积木报表扩展实现类放开注释 2024-06-22 20:06:13 +08:00
43d47c08cb 【jeecgboot 3.7.0里程碑版本发布——合并springboot3sas分支】
Merge remote-tracking branch 'origin/springboot3' into springboot3_sas

# Conflicts:
#	.gitignore
#	db/tables_nacos.sql
#	jeecg-boot-base-core/pom.xml
#	jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/AutoLogAspect.java
#	jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java
#	jeecg-boot-base-core/src/main/java/org/jeecg/config/DruidWallConfigRegister.java
#	jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
#	jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java
#	jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java
#	jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/service/impl/BaseCommonServiceImpl.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartRoleController.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDictController.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTableWhiteListController.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysAnnouncementServiceImpl.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysTenantPackServiceImpl.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserDepartServiceImpl.java
#	jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml
#	jeecg-module-system/jeecg-system-start/src/main/resources/application-prod.yml
#	jeecg-module-system/jeecg-system-start/src/main/resources/application-test.yml
#	pom.xml
2024-06-22 19:55:35 +08:00
e616c5d8fe Merge pull request #6243 from EightMonth/springboot3_sas
sas兼容shiro处理
2024-06-20 16:09:29 +08:00
cddf23c787 sas 兼容shiro处理 2024-05-31 14:29:21 +08:00
70a37309dd sas兼容shiro处理 2024-05-22 18:08:31 +08:00
48555b5219 Merge pull request #6201 from EightMonth/springboot3_sas
增加bug修复注释
2024-04-30 14:25:10 +08:00
06d58f202f 增加bug修复注释 2024-04-30 14:07:59 +08:00
628870af9b Merge pull request #6199 from EightMonth/springboot3_sas
修复#6168\#6169\websocket连接问题
2024-04-30 14:02:22 +08:00
b46a6438e6 修复#6168\#6169\websocket连接问题 2024-04-30 11:47:51 +08:00
5488f99723 Merge pull request #6194 from EightMonth/springboot3_sas
修复#6150,同时修复online表单无法加载问题
2024-04-29 17:34:06 +08:00
6bc1fe8d21 修复#6150,同时修复online表单无法加载问题 2024-04-29 17:27:25 +08:00
7cac16320c Merge pull request #6182 from EightMonth/springboot3_sas
修复Online同步数据库
2024-04-26 12:59:43 +08:00
24dbd1db39 修复Online同步数据库 2024-04-26 12:53:22 +08:00
46b026b989 Merge pull request #6092 from EightMonth/springboot3_sas
升级druid v1.2.22版本兼容处理
2024-04-08 15:26:41 +08:00
94c45f5e0f 升级druid v1.2.22版本兼容处理 2024-04-08 14:11:39 +08:00
8950e19d4e Merge pull request #6037 from EightMonth/springboot3_sas
修复 #5936
2024-03-25 15:00:06 +08:00
99eb88f71c 修复 #5936 2024-03-25 14:44:23 +08:00
824d7839d8 Merge pull request #6014 from EightMonth/springboot3_sas
支持手动生成token
2024-03-22 16:18:29 +08:00
c88f9d95d4 支持手动生成token 2024-03-19 17:16:12 +08:00
beb0bc2f64 Merge pull request #5995 from EightMonth/springboot3_sas
移除权限不足异常堆栈,权限加载加入缓存
2024-03-15 17:06:05 +08:00
f741db874c 移除权限不足异常堆栈,权限加载加入缓存 2024-03-15 13:55:58 +08:00
d684c09392 Merge pull request #5965 from EightMonth/springboot3_sas
新增token校验、客户端便捷工具类、修复登录缺乏租户信息、强退功能失效
2024-03-12 14:27:11 +08:00
364be22dd0 新增token校验、客户端便捷工具类、修复登录缺乏租户信息、强退功能失效 2024-03-08 16:30:23 +08:00
20efa3bf9a Merge pull request #5934 from EightMonth/springboot3_sas
修正springboot3 sas默认配置
2024-03-01 16:23:13 +08:00
c7977dda3d 添加nacos sql自动创建nacos库 2024-03-01 16:17:30 +08:00
c27c5a9a9b 梳理服务配置信息 2024-03-01 15:49:28 +08:00
0ab280f812 添加springboot3的配置变更 2024-03-01 14:59:40 +08:00
c3066dac17 修改认证异常类拦截 2024-03-01 14:51:16 +08:00
b650d512b3 修复 #5903 ,完善在微服务的sas认证 2024-03-01 14:51:09 +08:00
925ec9447d Merge pull request #5819 from EightMonth/springboot3_sas
打通三方登录&移除shiro
2024-01-17 13:55:58 +08:00
411a73c1bf 移除shiro 2024-01-16 19:49:42 +08:00
84077e6e24 移除shiro 2024-01-16 19:49:15 +08:00
184cf97304 打通三方登录 2024-01-16 19:09:56 +08:00
5f425b49b2 Merge pull request #5761 from EightMonth/springboot3_sas
升级 spring authorization server
2024-01-12 09:40:48 +08:00
3ac8ee304a 完全替换shiro权限注解,新增手机登录、APP登录 2024-01-12 09:26:30 +08:00
0faac01bb7 sas升级脚本 2024-01-04 11:27:33 +08:00
74d88a8fcc springboot sas升级 2024-01-04 11:27:23 +08:00
114 changed files with 9435 additions and 9592 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@ os_del.cmd
os_del_doc.cmd
.svn
derby.log
*.log

View File

@ -13,3 +13,4 @@ os_del.cmd
os_del_doc.cmd
.svn
derby.log
*.log

View File

@ -0,0 +1,45 @@
CREATE TABLE `oauth2_registered_client` (
`id` varchar(100) NOT NULL,
`client_id` varchar(100) NOT NULL,
`client_id_issued_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`client_secret` varchar(200) DEFAULT NULL,
`client_secret_expires_at` timestamp NULL DEFAULT NULL,
`client_name` varchar(200) NOT NULL,
`client_authentication_methods` varchar(1000) NOT NULL,
`authorization_grant_types` varchar(1000) NOT NULL,
`redirect_uris` varchar(1000) DEFAULT NULL,
`post_logout_redirect_uris` varchar(1000) DEFAULT NULL,
`scopes` varchar(1000) NOT NULL,
`client_settings` varchar(2000) NOT NULL,
`token_settings` varchar(2000) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO `oauth2_registered_client`
(`id`,
`client_id`,
`client_id_issued_at`,
`client_secret`,
`client_secret_expires_at`,
`client_name`,
`client_authentication_methods`,
`authorization_grant_types`,
`redirect_uris`,
`post_logout_redirect_uris`,
`scopes`,
`client_settings`,
`token_settings`)
VALUES
('3eacac0e-0de9-4727-9a64-6bdd4be2ee1f',
'jeecg-client',
now(),
'secret',
null,
'3eacac0e-0de9-4727-9a64-6bdd4be2ee1f',
'client_secret_basic',
'refresh_token,authorization_code,password,app,phone,social',
'http://127.0.0.1:8080/jeecg-',
'http://127.0.0.1:8080/',
'*',
'{"@class":"java.util.Collections$UnmodifiableMap","settings.client.require-proof-key":false,"settings.client.require-authorization-consent":true}',
'{"@class":"java.util.Collections$UnmodifiableMap","settings.token.reuse-refresh-tokens":true,"settings.token.id-token-signature-algorithm":["org.springframework.security.oauth2.jose.jws.SignatureAlgorithm","RS256"],"settings.token.access-token-time-to-live":["java.time.Duration",300000.000000000],"settings.token.access-token-format":{"@class":"org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat","value":"self-contained"},"settings.token.refresh-token-time-to-live":["java.time.Duration",3600.000000000],"settings.token.authorization-code-time-to-live":["java.time.Duration",300000.000000000],"settings.token.device-code-time-to-live":["java.time.Duration",300000.000000000]}');

View File

@ -192,81 +192,19 @@
<version>${java-jwt.version}</version>
</dependency>
<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>${shiro.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- shiro-redis -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>${shiro-redis.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
</exclusion>
<exclusion>
<artifactId>checkstyle</artifactId>
<groupId>com.puppycrawl.tools</groupId>
</exclusion>
<!-- TODO shiro 无法使用 spring boot 3.X 自带的jedis降版本处理 -->
<exclusion>
<artifactId>jedis</artifactId>
<groupId>redis.clients</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- TODO shiro 无法使用 spring boot 3.X 自带的jedis降版本处理 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<classifier>jakarta</classifier>
<version>${shiro.version}</version>
<!-- 排除仍使用了javax.servlet的依赖 -->
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入适配jakarta的依赖包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<classifier>jakarta</classifier>
<version>${shiro.version}</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<classifier>jakarta</classifier>
<version>${shiro.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
</exclusion>
</exclusions>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<!-- 添加spring security cas支持 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
</dependency>
<!-- knife4j -->

View File

@ -0,0 +1,21 @@
package org.apache.shiro;
import org.apache.shiro.subject.Subject;
/**
* 兼容处理Online功能使用处理请勿修改
* @author eightmonth@qq.com
* @date 2024/4/29 14:05
*/
public class SecurityUtils {
public static Subject getSubject() {
return new Subject() {
@Override
public Object getPrincipal() {
return Subject.super.getPrincipal();
}
};
}
}

View File

@ -0,0 +1,14 @@
package org.apache.shiro.subject;
import org.jeecg.config.security.utils.SecureUtil;
/**
* 兼容处理Online功能使用处理请勿修改
* @author eightmonth@qq.com
* @date 2024/4/29 14:18
*/
public interface Subject {
default Object getPrincipal() {
return SecureUtil.currentUser();
}
}

View File

@ -1,5 +1,6 @@
package org.jeecg.common.api;
import com.alibaba.fastjson.JSONObject;
import org.jeecg.common.system.vo.*;
import java.util.List;
@ -64,6 +65,13 @@ public interface CommonAPI {
*/
public String getUserIdByName(String username);
/**
* 5根据用户手机号查询用户信息
* @param username
* @return
*/
public LoginUser getUserByPhone(String phone);
/**
* 6字典表的 翻译
@ -144,4 +152,31 @@ public interface CommonAPI {
List<DictModel> translateDictFromTableByKeys(String table, String text, String code, String keys, String dataSource);
//update-end---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
/**
* 登录加载系统字典
* @return
*/
Map<String,List<DictModel>> queryAllDictItems();
/**
* 查询SysDepart集合
* @param userId
* @return
*/
List<SysDepartModel> queryUserDeparts(String userId);
/**
* 根据用户名设置部门ID
* @param username
* @param orgCode
*/
void updateUserDepart(String username,String orgCode,Integer loginTenantId);
/**
* 设置登录租户
* @param username
* @return
*/
JSONObject setLoginTenant(String username);
}

View File

@ -1,5 +1,6 @@
package org.jeecg.common.aspect;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PropertyFilter;
import org.apache.shiro.SecurityUtils;
@ -15,13 +16,14 @@ import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.enums.ModuleType;
import org.jeecg.common.constant.enums.OperateTypeEnum;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.IpUtils;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
@ -101,7 +103,7 @@ public class AutoLogAspect {
//设置IP地址
dto.setIp(IpUtils.getIpAddr(request));
//获取登录用户信息
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
if(sysUser!=null){
dto.setUserid(sysUser.getUsername());
dto.setUsername(sysUser.getRealname());

View File

@ -90,7 +90,7 @@ public interface CommonConstant {
/** 登录用户Shiro权限缓存KEY前缀 */
public static String PREFIX_USER_SHIRO_CACHE = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:";
/** 登录用户Token令牌缓存KEY前缀 */
String PREFIX_USER_TOKEN = "prefix_user_token:";
String PREFIX_USER_TOKEN = "token::jeecg-client::";
// /** Token缓存时间3600秒即一小时 */
// int TOKEN_EXPIRE_TIME = 3600;

View File

@ -6,8 +6,6 @@ import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.jeecg.common.api.dto.LogDTO;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
@ -24,6 +22,8 @@ import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.connection.PoolException;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.util.CollectionUtils;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ -43,9 +43,27 @@ import java.util.Map;
@RestControllerAdvice
@Slf4j
public class JeecgBootExceptionHandler {
@Resource
@Resource
BaseCommonService baseCommonService;
/**
* 验证码错误异常
*/
@ExceptionHandler(JeecgCaptchaException.class)
@ResponseStatus(HttpStatus.OK)
public Result<?> handleJeecgCaptchaException(JeecgCaptchaException e) {
log.error(e.getMessage(), e);
return Result.error(e.getCode(), e.getMessage());
}
@ExceptionHandler(AuthenticationException.class)
@ResponseStatus(HttpStatus.OK)
public Result<?> handleJeecgCaptchaException(AuthenticationException e) {
log.error(e.getMessage(), e);
return Result.error(401, e.getMessage());
}
/**
* 处理自定义异常
@ -101,8 +119,8 @@ public class JeecgBootExceptionHandler {
return Result.error("数据库中已存在该记录");
}
@ExceptionHandler({UnauthorizedException.class, AuthorizationException.class})
public Result<?> handleAuthorizationException(AuthorizationException e){
@ExceptionHandler(AccessDeniedException.class)
public Result<?> handleAuthorizationException(AccessDeniedException e){
log.error(e.getMessage(), e);
return Result.noauth("没有权限,请联系管理员授权,后刷新缓存!");
}

View File

@ -0,0 +1,28 @@
package org.jeecg.common.exception;
import lombok.Data;
/**
* @author kezhijie@wuhandsj.com
* @date 2024/1/2 11:38
*/
@Data
public class JeecgCaptchaException extends RuntimeException{
private Integer code;
private static final long serialVersionUID = -9093410345065209053L;
public JeecgCaptchaException(Integer code, String message) {
super(message);
this.code = code;
}
public JeecgCaptchaException(String message, Throwable cause) {
super(message, cause);
}
public JeecgCaptchaException(Throwable cause) {
super(cause);
}
}

View File

@ -1,17 +1,18 @@
package org.jeecg.common.system.base.controller;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
@ -19,6 +20,7 @@ import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
@ -51,7 +53,7 @@ public class JeecgController<T, S extends IService<T>> {
protected ModelAndView exportXls(HttpServletRequest request, T object, Class<T> clazz, String title) {
// Step.1 组装查询条件
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
// 过滤选中数据
String selections = request.getParameter("selections");
@ -89,7 +91,7 @@ public class JeecgController<T, S extends IService<T>> {
protected ModelAndView exportXlsSheet(HttpServletRequest request, T object, Class<T> clazz, String title,String exportFields,Integer pageNum) {
// Step.1 组装查询条件
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
// Step.2 计算分页sheet数据
double total = service.count();
int count = (int)Math.ceil(total/pageNum);

View File

@ -1,5 +1,7 @@
package org.jeecg.common.system.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
@ -10,14 +12,17 @@ import com.google.common.base.Joiner;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.DataBaseConstant;
@ -29,6 +34,22 @@ import org.jeecg.common.system.vo.SysUserCacheInfo;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.security.self.SelfAuthenticationProvider;
import org.jeecg.config.security.self.SelfAuthenticationToken;
import org.jeecg.config.security.utils.SecureUtil;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.*;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
/**
* @Author Scott
@ -42,6 +63,8 @@ public class JwtUtil {
public static final long EXPIRE_TIME = (7 * 12) * 60 * 60 * 1000;
static final String WELL_NUMBER = SymbolConstant.WELL_NUMBER + SymbolConstant.LEFT_CURLY_BRACKET;
public static final String DEFAULT_CLIENT = "jeecg-client";
/**
*
* @param response
@ -77,10 +100,9 @@ public class JwtUtil {
public static boolean verify(String token, String username, String secret) {
try {
// 根据密码生成JWT效验器
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
JwtDecoder jwtDecoder = SpringContextUtils.getBean(JwtDecoder.class);
// 效验TOKEN
DecodedJWT jwt = verifier.verify(token);
jwtDecoder.decode(token);
return true;
} catch (Exception exception) {
return false;
@ -102,17 +124,25 @@ public class JwtUtil {
}
/**
* 生成签名,5min后过期
* 生成token
*
* @param username 用户名
* @param secret 用户的密码
* @return 加密的token
*/
public static String sign(String username, String secret) {
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(secret);
// 附带username信息
return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
Map<String, Object> additionalParameter = new HashMap<>();
additionalParameter.put("username", username);
RegisteredClientRepository registeredClientRepository = SpringContextUtils.getBean(RegisteredClientRepository.class);
SelfAuthenticationProvider selfAuthenticationProvider = SpringContextUtils.getBean(SelfAuthenticationProvider.class);
OAuth2ClientAuthenticationToken client = new OAuth2ClientAuthenticationToken(Objects.requireNonNull(registeredClientRepository.findByClientId("jeecg-client")), ClientAuthenticationMethod.CLIENT_SECRET_BASIC, null);
client.setAuthenticated(true);
SelfAuthenticationToken selfAuthenticationToken = new SelfAuthenticationToken(client, additionalParameter);
selfAuthenticationToken.setAuthenticated(true);
OAuth2AccessTokenAuthenticationToken accessToken = (OAuth2AccessTokenAuthenticationToken) selfAuthenticationProvider.authenticate(selfAuthenticationToken);
return accessToken.getAccessToken().getTokenValue();
}
@ -177,7 +207,7 @@ public class JwtUtil {
//2.通过shiro获取登录用户信息
LoginUser sysUser = null;
try {
sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
sysUser = SecureUtil.currentUser();
} catch (Exception e) {
log.warn("SecurityUtils.getSubject() 获取用户信息异常:" + e.getMessage());
}

View File

@ -1,13 +1,18 @@
package org.jeecg.common.system.vo;
import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecg.common.desensitization.annotation.SensitiveField;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.io.Serializable;
import java.util.Date;
import java.util.Set;
/**
* <p>
@ -20,8 +25,10 @@ import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class LoginUser {
public class LoginUser implements Serializable {
private static final long serialVersionUID = -7143159031677245866L;
/**
* 登录人id
*/
@ -138,4 +145,29 @@ public class LoginUser {
/**设备id uniapp推送用*/
private String clientId;
@SensitiveField
private String salt;
@Override
public String toString() {
// 重新构建对象过滤一些敏感字段
LoginUser loginUser = new LoginUser();
loginUser.setId(id);
loginUser.setUsername(username);
loginUser.setRealname(realname);
loginUser.setOrgCode(orgCode);
loginUser.setSex(sex);
loginUser.setEmail(email);
loginUser.setPhone(phone);
loginUser.setDelFlag(delFlag);
loginUser.setStatus(status);
loginUser.setActivitiSync(activitiSync);
loginUser.setUserIdentity(userIdentity);
loginUser.setDepartIds(departIds);
loginUser.setPost(post);
loginUser.setTelephone(telephone);
loginUser.setRelTenantIds(relTenantIds);
loginUser.setClientId(clientId);
return JSON.toJSONString(loginUser);
}
}

View File

@ -1,5 +1,6 @@
package org.jeecg.common.util;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.CommonAPI;
@ -11,8 +12,6 @@ import org.jeecg.common.exception.JeecgBoot401Exception;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import jakarta.servlet.http.HttpServletRequest;
/**
* @Author scott
* @Date 2019/9/23 14:12
@ -106,8 +105,8 @@ public class TokenUtils {
}
// 查询用户信息
LoginUser user = TokenUtils.getLoginUser(username, commonApi, redisUtil);
//LoginUser user = commonApi.getUserByName(username);
//LoginUser user = TokenUtils.getLoginUser(username, commonApi, redisUtil);
LoginUser user = commonApi.getUserByName(username);
if (user == null) {
throw new JeecgBoot401Exception("用户不存在!");
}
@ -158,10 +157,11 @@ public class TokenUtils {
//【重要】此处通过redis原生获取缓存用户是为了解决微服务下system服务挂了其他服务互调不通问题---
if (redisUtil.hasKey(loginUserKey)) {
try {
loginUser = (LoginUser) redisUtil.get(loginUserKey);
Object obj = redisUtil.get(loginUserKey);
loginUser = (LoginUser) obj;
//解密用户
SensitiveInfoUtil.handlerObject(loginUser, false);
} catch (IllegalAccessException e) {
} catch (Exception e) {
e.printStackTrace();
}
} else {

View File

@ -1,10 +1,9 @@
package org.jeecg.common.util.encryption;
import org.apache.shiro.codec.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
/**
* @Description: AES 加密
@ -49,7 +48,7 @@ public class AesEncryptUtil {
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(plaintext);
return Base64.encodeToString(encrypted);
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
e.printStackTrace();
@ -67,7 +66,7 @@ public class AesEncryptUtil {
*/
public static String desEncrypt(String data, String key, String iv) throws Exception {
//update-begin-author:taoyan date:2022-5-23 for:VUEN-1084 【vue3】online表单测试发现的新问题 6、解密报错 ---解码失败应该把异常抛出去,在外面处理
byte[] encrypted1 = Base64.decode(data);
byte[] encrypted1 = Base64.getDecoder().decode(data);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");

View File

@ -32,10 +32,6 @@ public class JeecgBaseConfig {
*/
private Firewall firewall;
/**
* shiro拦截排除
*/
private Shiro shiro;
/**
* 上传文件配置
*/
@ -88,14 +84,6 @@ public class JeecgBaseConfig {
this.signatureSecret = signatureSecret;
}
public Shiro getShiro() {
return shiro;
}
public void setShiro(Shiro shiro) {
this.shiro = shiro;
}
public Path getPath() {
return path;
}

View File

@ -2,19 +2,16 @@ package org.jeecg.config.firewall.interceptor;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.CommonUtils;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.firewall.interceptor.enums.LowCodeUrlsEnum;
import org.jeecg.config.security.utils.SecureUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;
import jakarta.annotation.Resource;
@ -66,7 +63,7 @@ public class LowCodeModeInterceptor implements HandlerInterceptor {
if (jeecgBaseConfig.getFirewall()!=null && LowCodeModeInterceptor.LOW_CODE_MODE_PROD.equals(jeecgBaseConfig.getFirewall().getLowCodeMode())) {
String requestURI = request.getRequestURI().substring(request.getContextPath().length());
log.info("低代码模式,拦截请求路径:" + requestURI);
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser loginUser = SecureUtil.currentUser();
Set<String> hasRoles = null;
if (loginUser == null) {
loginUser = commonAPI.getUserByName(JwtUtil.getUserNameByToken(SpringContextUtils.getHttpServletRequest()));

View File

@ -6,13 +6,13 @@ import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.TenantConstant;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.security.utils.SecureUtil;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
@ -192,7 +192,7 @@ public class MybatisInterceptor implements Interceptor {
private LoginUser getLoginUser() {
LoginUser sysUser = null;
try {
sysUser = SecurityUtils.getSubject().getPrincipal() != null ? (LoginUser) SecurityUtils.getSubject().getPrincipal() : null;
sysUser = SecureUtil.currentUser() != null ? SecureUtil.currentUser() : null;
} catch (Exception e) {
//e.printStackTrace();
sysUser = null;

View File

@ -0,0 +1,90 @@
package org.jeecg.config.security;
import lombok.AllArgsConstructor;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.Set;
/**
* spring authorization server 注册客户端便捷工具类
* @author eightmonth@qq.com
* @date 2024/3/7 11:22
*/
@Component
@AllArgsConstructor
public class ClientService {
private RegisteredClientRepository registeredClientRepository;
/**
* 修改客户端token有效期
* 认证码、设备码有效期与accessToken有效期保持一致
*/
public void updateTokenValidation(String clientId, Long accessTokenValidation, Long refreshTokenValidation){
RegisteredClient registeredClient = findByClientId(clientId);
RegisteredClient.Builder builder = RegisteredClient.from(registeredClient);
TokenSettings tokenSettings = TokenSettings.builder()
.idTokenSignatureAlgorithm(SignatureAlgorithm.RS256)
.accessTokenTimeToLive(Duration.ofSeconds(accessTokenValidation))
.accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED)
.reuseRefreshTokens(true)
.refreshTokenTimeToLive(Duration.ofSeconds(refreshTokenValidation))
.authorizationCodeTimeToLive(Duration.ofSeconds(accessTokenValidation))
.deviceCodeTimeToLive(Duration.ofSeconds(accessTokenValidation))
.build();
builder.tokenSettings(tokenSettings);
registeredClientRepository.save(builder.build());
}
/**
* 修改客户端授权类型
* @param clientId
* @param grantTypes
*/
public void updateGrantType(String clientId, Set<AuthorizationGrantType> grantTypes) {
RegisteredClient registeredClient = findByClientId(clientId);
RegisteredClient.Builder builder = RegisteredClient.from(registeredClient);
for (AuthorizationGrantType grantType : grantTypes) {
builder.authorizationGrantType(grantType);
}
registeredClientRepository.save(builder.build());
}
/**
* 修改客户端重定向uri
* @param clientId
* @param redirectUris
*/
public void updateRedirectUris(String clientId, String redirectUris) {
RegisteredClient registeredClient = findByClientId(clientId);
RegisteredClient.Builder builder = RegisteredClient.from(registeredClient);
builder.redirectUri(redirectUris);
registeredClientRepository.save(builder.build());
}
/**
* 修改客户端授权范围
* @param clientId
* @param scopes
*/
public void updateScopes(String clientId, Set<String> scopes) {
RegisteredClient registeredClient = findByClientId(clientId);
RegisteredClient.Builder builder = RegisteredClient.from(registeredClient);
for (String scope : scopes) {
builder.scope(scope);
}
registeredClientRepository.save(builder.build());
}
public RegisteredClient findByClientId(String clientId) {
return registeredClientRepository.findByClientId(clientId);
}
}

View File

@ -0,0 +1,45 @@
package org.jeecg.config.security;
import io.undertow.servlet.spec.HttpServletRequestImpl;
import io.undertow.util.HttpString;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
/**
* 复制仪盘表请求query体携带的token
* @author eightmonth
* @date 2024/7/3 14:04
*/
@Component
@Order(value = Integer.MIN_VALUE)
public class CopyTokenFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 以下为undertow定制代码如切换其它servlet容器需要同步更换
HttpServletRequestImpl undertowRequest = (HttpServletRequestImpl) request;
String token = request.getHeader("Authorization");
if (StringUtils.hasText(token)) {
undertowRequest.getExchange().getRequestHeaders().remove("Authorization");
undertowRequest.getExchange().getRequestHeaders().add(new HttpString("Authorization"), "bearer " + token);
} else {
String bearerToken = request.getParameter("token");
String headerBearerToken = request.getHeader("X-Access-Token");
if (StringUtils.hasText(bearerToken)) {
undertowRequest.getExchange().getRequestHeaders().add(new HttpString("Authorization"), "bearer " + bearerToken);
} else if (StringUtils.hasText(headerBearerToken)) {
undertowRequest.getExchange().getRequestHeaders().add(new HttpString("Authorization"), "bearer " + headerBearerToken);
}
}
filterChain.doFilter(undertowRequest, response);
}
}

View File

@ -0,0 +1,32 @@
package org.jeecg.config.security;
import lombok.RequiredArgsConstructor;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.system.vo.LoginUser;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
/**
* token只存储用户名与过期时间
* 这里通过取用户名转全量用户信息存储到Security中
* @author eightmonth@qq.com
* @date 2024/7/15 11:05
*/
@Component
@RequiredArgsConstructor
public class JeecgAuthenticationConvert implements Converter<Jwt, AbstractAuthenticationToken> {
private final CommonAPI commonAPI;
@Override
public AbstractAuthenticationToken convert(Jwt source) {
String username = source.getClaims().get("username").toString();
LoginUser loginUser = commonAPI.getUserByName(username);
return new UsernamePasswordAuthenticationToken(loginUser, null, new ArrayList<>());
}
}

View File

@ -0,0 +1,135 @@
package org.jeecg.config.security;
import org.jeecg.common.system.util.JwtUtil;
import org.springframework.lang.Nullable;
import org.springframework.security.oauth2.core.ClaimAccessor;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.jwt.JwsHeader;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.token.*;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalUnit;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* @author eightmonth@qq.com
* @date 2024/7/11 17:10
*/
public class JeecgOAuth2AccessTokenGenerator implements OAuth2TokenGenerator<OAuth2AccessToken> {
private final JwtEncoder jwtEncoder;
private OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer;
public JeecgOAuth2AccessTokenGenerator(JwtEncoder jwtEncoder) {
this.jwtEncoder = jwtEncoder;
}
@Nullable
@Override
public OAuth2AccessToken generate(OAuth2TokenContext context) {
if (!OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) {
return null;
}
String issuer = null;
if (context.getAuthorizationServerContext() != null) {
issuer = context.getAuthorizationServerContext().getIssuer();
}
RegisteredClient registeredClient = context.getRegisteredClient();
Instant issuedAt = Instant.now();
Instant expiresAt = issuedAt.plusMillis(JwtUtil.EXPIRE_TIME);
OAuth2TokenClaimsSet.Builder claimsBuilder = OAuth2TokenClaimsSet.builder();
if (StringUtils.hasText(issuer)) {
claimsBuilder.issuer(issuer);
}
claimsBuilder
.subject(context.getPrincipal().getName())
.audience(Collections.singletonList(registeredClient.getClientId()))
.issuedAt(issuedAt)
.expiresAt(expiresAt)
.notBefore(issuedAt)
.id(UUID.randomUUID().toString());
if (!CollectionUtils.isEmpty(context.getAuthorizedScopes())) {
claimsBuilder.claim(OAuth2ParameterNames.SCOPE, context.getAuthorizedScopes());
}
if (this.accessTokenCustomizer != null) {
OAuth2TokenClaimsContext.Builder accessTokenContextBuilder = OAuth2TokenClaimsContext.with(claimsBuilder)
.registeredClient(context.getRegisteredClient())
.principal(context.getPrincipal())
.authorizationServerContext(context.getAuthorizationServerContext())
.authorizedScopes(context.getAuthorizedScopes())
.tokenType(context.getTokenType())
.authorizationGrantType(context.getAuthorizationGrantType());
if (context.getAuthorization() != null) {
accessTokenContextBuilder.authorization(context.getAuthorization());
}
if (context.getAuthorizationGrant() != null) {
accessTokenContextBuilder.authorizationGrant(context.getAuthorizationGrant());
}
OAuth2TokenClaimsContext accessTokenContext = accessTokenContextBuilder.build();
this.accessTokenCustomizer.customize(accessTokenContext);
}
OAuth2TokenClaimsSet accessTokenClaimsSet = claimsBuilder.build();
OAuth2AuthorizationGrantAuthenticationToken oAuth2ResourceOwnerBaseAuthenticationToken = context.getAuthorizationGrant();
String username = (String) oAuth2ResourceOwnerBaseAuthenticationToken.getAdditionalParameters().get("username");
String tokenValue = jwtEncoder.encode(JwtEncoderParameters.from(JwsHeader.with(SignatureAlgorithm.ES256).keyId("jeecg").build(),
JwtClaimsSet.builder().claim("username", username).expiresAt(expiresAt).build())).getTokenValue();
//此处可以做改造将tokenValue随机数换成用户信息方便后续多系统token互通认证通过解密token得到username
return new OAuth2AccessTokenClaims(OAuth2AccessToken.TokenType.BEARER, tokenValue,
accessTokenClaimsSet.getIssuedAt(), accessTokenClaimsSet.getExpiresAt(), context.getAuthorizedScopes(),
accessTokenClaimsSet.getClaims());
}
/**
* Sets the {@link OAuth2TokenCustomizer} that customizes the
* {@link OAuth2TokenClaimsContext#getClaims() claims} for the
* {@link OAuth2AccessToken}.
* @param accessTokenCustomizer the {@link OAuth2TokenCustomizer} that customizes the
* claims for the {@code OAuth2AccessToken}
*/
public void setAccessTokenCustomizer(OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer) {
Assert.notNull(accessTokenCustomizer, "accessTokenCustomizer cannot be null");
this.accessTokenCustomizer = accessTokenCustomizer;
}
private static final class OAuth2AccessTokenClaims extends OAuth2AccessToken implements ClaimAccessor {
private final Map<String, Object> claims;
private OAuth2AccessTokenClaims(TokenType tokenType, String tokenValue, Instant issuedAt, Instant expiresAt,
Set<String> scopes, Map<String, Object> claims) {
super(tokenType, tokenValue, issuedAt, expiresAt, scopes);
this.claims = claims;
}
@Override
public Map<String, Object> getClaims() {
return this.claims;
}
}
}

View File

@ -0,0 +1,100 @@
package org.jeecg.config.security;
import cn.hutool.core.util.ArrayUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.config.security.utils.SecureUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;
import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
/**
* spring authorization server自定义权限处理根据@PreAuthorize注解判断当前用户是否具备权限
* @author EightMonth
* @date 2024/1/10 17:00
*/
@Service("jps")
@AllArgsConstructor
@Slf4j
public class JeecgPermissionService {
private final String SPLIT = "::";
private final String PERM_PREFIX = "jps" + SPLIT;
private final CommonAPI commonAPI;
private final RedisUtil redisUtil;
/**
* 判断接口是否有任意xxxxxx权限
* @param permissions 权限
* @return {boolean}
*/
public boolean requiresPermissions(String... permissions) {
if (ArrayUtil.isEmpty(permissions)) {
return false;
}
LoginUser loginUser = SecureUtil.currentUser();
Object cache = redisUtil.get(buildKey("permission", loginUser.getId()));
Set<String> permissionList;
if (Objects.nonNull(cache)) {
permissionList = (Set<String>) cache;
} else {
permissionList = commonAPI.queryUserAuths(loginUser.getId());
redisUtil.set(buildKey("permission", loginUser.getId()), permissionList);
}
boolean pass = permissionList.stream().filter(StringUtils::hasText)
.anyMatch(x -> PatternMatchUtils.simpleMatch(permissions, x));
if (!pass) {
log.error("权限不足,缺少权限:"+ Arrays.toString(permissions));
}
return pass;
}
/**
* 判断接口是否有任意xxxxxx角色
* @param roles 角色
* @return {boolean}
*/
public boolean requiresRoles(String... roles) {
if (ArrayUtil.isEmpty(roles)) {
return false;
}
LoginUser loginUser = SecureUtil.currentUser();
Object cache = redisUtil.get(buildKey("role", loginUser.getUsername()));
Set<String> roleList;
if (Objects.nonNull(cache)) {
roleList = (Set<String>) cache;
} else {
roleList = commonAPI.queryUserRoles(loginUser.getUsername());
redisUtil.set(buildKey("role", loginUser.getUsername()), roleList);
}
boolean pass = roleList.stream().filter(StringUtils::hasText)
.anyMatch(x -> PatternMatchUtils.simpleMatch(roles, x));
if (!pass) {
log.error("权限不足,缺少角色:" + Arrays.toString(roles));
}
return pass;
}
/**
* 由于缓存key是以人的维度角色列表、权限列表在值中jeecg是以权限列表绑定在角色上形成的权限集合
* 权限发生变更时,需要清理全部人的权限缓存
*/
public void clearCache() {
redisUtil.removeAll(PERM_PREFIX);
}
private String buildKey(String type, String username) {
return PERM_PREFIX + type + SPLIT + username;
}
}

View File

@ -0,0 +1,54 @@
package org.jeecg.config.security;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.util.concurrent.TimeUnit;
/**
* spring authorization server 自定义redis保存授权范围信息
*/
@Component
@RequiredArgsConstructor
public class JeecgRedisOAuth2AuthorizationConsentService implements OAuth2AuthorizationConsentService {
private final RedisTemplate<String, Object> redisTemplate;
private final static Long TIMEOUT = 10L;
@Override
public void save(OAuth2AuthorizationConsent authorizationConsent) {
Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
redisTemplate.opsForValue().set(buildKey(authorizationConsent), authorizationConsent, TIMEOUT,
TimeUnit.MINUTES);
}
@Override
public void remove(OAuth2AuthorizationConsent authorizationConsent) {
Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
redisTemplate.delete(buildKey(authorizationConsent));
}
@Override
public OAuth2AuthorizationConsent findById(String registeredClientId, String principalName) {
Assert.hasText(registeredClientId, "registeredClientId cannot be empty");
Assert.hasText(principalName, "principalName cannot be empty");
return (OAuth2AuthorizationConsent) redisTemplate.opsForValue()
.get(buildKey(registeredClientId, principalName));
}
private static String buildKey(String registeredClientId, String principalName) {
return "token:consent:" + registeredClientId + ":" + principalName;
}
private static String buildKey(OAuth2AuthorizationConsent authorizationConsent) {
return buildKey(authorizationConsent.getRegisteredClientId(), authorizationConsent.getPrincipalName());
}
}

View File

@ -0,0 +1,181 @@
package org.jeecg.config.security;
import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.lang.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* spring authorization server自定义redis保存认证信息
* @author EightMonth
*/
@Component
@RequiredArgsConstructor
public class JeecgRedisOAuth2AuthorizationService implements OAuth2AuthorizationService {
private final static Long TIMEOUT = 10L;
private static final String AUTHORIZATION = "token";
private final RedisTemplate<String, Object> redisTemplate;
@Override
public void save(OAuth2Authorization authorization) {
Assert.notNull(authorization, "authorization cannot be null");
if (isState(authorization)) {
String token = authorization.getAttribute("state");
redisTemplate.setValueSerializer(RedisSerializer.java());
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.STATE, token), authorization, TIMEOUT,
TimeUnit.MINUTES);
}
if (isCode(authorization)) {
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
.getToken(OAuth2AuthorizationCode.class);
OAuth2AuthorizationCode authorizationCodeToken = authorizationCode.getToken();
long between = ChronoUnit.MINUTES.between(authorizationCodeToken.getIssuedAt(),
authorizationCodeToken.getExpiresAt());
redisTemplate.setValueSerializer(RedisSerializer.java());
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()),
authorization, between, TimeUnit.MINUTES);
}
if (isRefreshToken(authorization)) {
OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken();
long between = ChronoUnit.SECONDS.between(refreshToken.getIssuedAt(), refreshToken.getExpiresAt());
redisTemplate.setValueSerializer(RedisSerializer.java());
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken.getTokenValue()),
authorization, between, TimeUnit.SECONDS);
}
if (isAccessToken(authorization)) {
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
long between = ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt());
redisTemplate.setValueSerializer(RedisSerializer.java());
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()),
authorization, between, TimeUnit.SECONDS);
// 扩展记录 access-token 、username 的关系 1::token::username::admin::xxx
String tokenUsername = String.format("%s::%s::%s", AUTHORIZATION, authorization.getPrincipalName(), accessToken.getTokenValue());
redisTemplate.opsForValue().set(tokenUsername, accessToken.getTokenValue(), between, TimeUnit.SECONDS);
}
}
@Override
public void remove(OAuth2Authorization authorization) {
Assert.notNull(authorization, "authorization cannot be null");
List<String> keys = new ArrayList<>();
if (isState(authorization)) {
String token = authorization.getAttribute("state");
keys.add(buildKey(OAuth2ParameterNames.STATE, token));
}
if (isCode(authorization)) {
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
.getToken(OAuth2AuthorizationCode.class);
OAuth2AuthorizationCode authorizationCodeToken = authorizationCode.getToken();
keys.add(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()));
}
if (isRefreshToken(authorization)) {
OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken();
keys.add(buildKey(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken.getTokenValue()));
}
if (isAccessToken(authorization)) {
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
keys.add(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()));
// 扩展记录 access-token 、username 的关系 1::token::username::admin::xxx
String key = String.format("%s::%s::%s", AUTHORIZATION, authorization.getPrincipalName(), accessToken.getTokenValue());
keys.add(key);
}
redisTemplate.delete(keys);
}
@Override
@Nullable
public OAuth2Authorization findById(String id) {
throw new UnsupportedOperationException();
}
@Override
@Nullable
public OAuth2Authorization findByToken(String token, @Nullable OAuth2TokenType tokenType) {
Assert.hasText(token, "token cannot be empty");
Assert.notNull(tokenType, "tokenType cannot be empty");
redisTemplate.setValueSerializer(RedisSerializer.java());
return (OAuth2Authorization) redisTemplate.opsForValue().get(buildKey(tokenType.getValue(), token));
}
private String buildKey(String type, String id) {
return String.format("%s::%s::%s", AUTHORIZATION, type, id);
}
private static boolean isState(OAuth2Authorization authorization) {
return Objects.nonNull(authorization.getAttribute("state"));
}
private static boolean isCode(OAuth2Authorization authorization) {
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
.getToken(OAuth2AuthorizationCode.class);
return Objects.nonNull(authorizationCode);
}
private static boolean isRefreshToken(OAuth2Authorization authorization) {
return Objects.nonNull(authorization.getRefreshToken());
}
private static boolean isAccessToken(OAuth2Authorization authorization) {
return Objects.nonNull(authorization.getAccessToken());
}
/**
* 扩展方法根据 username 查询是否存在存储的
* @param authentication
* @return
*/
public void removeByUsername(Authentication authentication) {
// 根据 username查询对应access-token
String authenticationName = authentication.getName();
// 扩展记录 access-token 、username 的关系 1::token::username::admin::xxx
String tokenUsernameKey = String.format("%s::%s::*", AUTHORIZATION, authenticationName);
Set<String> keys = redisTemplate.keys(tokenUsernameKey);
if (CollUtil.isEmpty(keys)) {
return;
}
List<Object> tokenList = redisTemplate.opsForValue().multiGet(keys);
for (Object token : tokenList) {
// 根据token 查询存储的 OAuth2Authorization
OAuth2Authorization authorization = this.findByToken((String) token, OAuth2TokenType.ACCESS_TOKEN);
// 根据 OAuth2Authorization 删除相关令牌
this.remove(authorization);
}
}
}

View File

@ -0,0 +1,38 @@
package org.jeecg.config.security;
/**
* 登录模式
* @author EightMonth
* @date 2024/1/10 17:43
*/
public class LoginType {
/**
* 密码模式
*/
public static final String PASSWORD = "password";
/**
* 手机号+验证码模式
*/
public static final String PHONE = "phone";
/**
* app登录
*/
public static final String APP = "app";
/**
* 扫码登录
*/
public static final String SCAN = "scan";
/**
* 所有联合登录比如github\钉钉\企业微信\微信
*/
public static final String SOCIAL = "social";
public static final String SELF = "self";
}

View File

@ -0,0 +1,49 @@
package org.jeecg.config.security;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.jeecg.common.system.util.JwtUtil;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.resource.BearerTokenErrors;
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.Objects;
/**
* 当用户被强退时使客户端token失效
* @author eightmonth@qq.com
* @date 2024/3/7 17:30
*/
@Component
@AllArgsConstructor
public class RedisTokenValidationFilter extends OncePerRequestFilter {
private OAuth2AuthorizationService authorizationService;
private JwtDecoder jwtDecoder;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 从请求中获取token
DefaultBearerTokenResolver defaultBearerTokenResolver = new DefaultBearerTokenResolver();
String token = defaultBearerTokenResolver.resolve(request);
if (Objects.nonNull(token)) {
// 检查认证信息是否已被清除如果已被清除则令该token失效
OAuth2Authorization oAuth2Authorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
if (Objects.isNull(oAuth2Authorization)) {
throw new OAuth2AuthenticationException(BearerTokenErrors.invalidToken("认证信息已失效,请重新登录"));
}
}
filterChain.doFilter(request, response);
}
}

View File

@ -0,0 +1,240 @@
package org.jeecg.config.security;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.jeecg.config.security.app.AppGrantAuthenticationConvert;
import org.jeecg.config.security.app.AppGrantAuthenticationProvider;
import org.jeecg.config.security.password.PasswordGrantAuthenticationConvert;
import org.jeecg.config.security.password.PasswordGrantAuthenticationProvider;
import org.jeecg.config.security.phone.PhoneGrantAuthenticationConvert;
import org.jeecg.config.security.phone.PhoneGrantAuthenticationProvider;
import org.jeecg.config.security.social.SocialGrantAuthenticationConvert;
import org.jeecg.config.security.social.SocialGrantAuthenticationProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.token.*;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.util.Arrays;
/**
* spring authorization server核心配置
* @author eightmonth@qq.com
* @date 2024/1/2 9:29
*/
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@AllArgsConstructor
public class SecurityConfig {
private JdbcTemplate jdbcTemplate;
private OAuth2AuthorizationService authorizationService;
private JeecgAuthenticationConvert jeecgAuthenticationConvert;
@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
// 注册自定义登录类型
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.tokenEndpoint(tokenEndpoint -> tokenEndpoint.accessTokenRequestConverter(new PasswordGrantAuthenticationConvert())
.authenticationProvider(new PasswordGrantAuthenticationProvider(authorizationService, tokenGenerator())))
.tokenEndpoint(tokenEndpoint -> tokenEndpoint.accessTokenRequestConverter(new PhoneGrantAuthenticationConvert())
.authenticationProvider(new PhoneGrantAuthenticationProvider(authorizationService, tokenGenerator())))
.tokenEndpoint(tokenEndpoint -> tokenEndpoint.accessTokenRequestConverter(new AppGrantAuthenticationConvert())
.authenticationProvider(new AppGrantAuthenticationProvider(authorizationService, tokenGenerator())))
.tokenEndpoint(tokenEndpoint -> tokenEndpoint.accessTokenRequestConverter(new SocialGrantAuthenticationConvert())
.authenticationProvider(new SocialGrantAuthenticationProvider(authorizationService, tokenGenerator())))
//开启OpenID Connect 1.0其中oidc为OpenID Connect的缩写。 访问 /.well-known/openid-configuration即可获取认证信息
.oidc(Customizer.withDefaults());
http
//将需要认证的请求重定向到login页面行登录认证。
.exceptionHandling((exceptions) -> exceptions
.defaultAuthenticationEntryPointFor(
new LoginUrlAuthenticationEntryPoint("/sys/login"),
new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
)
);
return http.build();
}
@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
throws Exception {
http
//设置所有请求都需要认证未认证的请求都被重定向到login页面进行登录
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/cas/client/validateLogin")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/randomImage/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/checkCaptcha")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/login")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/mLogin")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/logout")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/thirdLogin/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/getEncryptedString")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/sms")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/phoneLogin")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/user/checkOnlyUser")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/user/register")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/user/phoneVerification")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/user/passwordChange")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/auth/2step-code")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/common/static/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/common/pdf/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/generic/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/getLoginQrcode/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/getQrcodeToken/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/checkAuth")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/doc.html")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.js")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.css")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.html")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.svg")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.pdf")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.jpg")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.png")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.gif")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.ico")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.ttf")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.woff")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.woff2")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/druid/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/swagger-ui.html")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/swagger**/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/webjars/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/v3/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/WW_verify*")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/annountCement/show/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/jmreport/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.js.map")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**/*.css.map")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/list")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/view")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/onlDragDatasetHead/getLoginUser")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/page/queryById")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/onlDragDatasetHead/getAllChartData")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/onlDragDatasetHead/getTotalData")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/drag/mock/json/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/test/bigScreen/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/bigscreen/template1/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/bigscreen/template1/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/websocket/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/newsWebsocket/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/vxeSocket/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/test/seata/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/error")).permitAll()
.anyRequest().authenticated()
)
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
.cors(cors -> cors
.configurationSource(req -> {
CorsConfiguration config = new CorsConfiguration();
config.applyPermitDefaultValues();
config.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
return config;
}))
.csrf(AbstractHttpConfigurer::disable)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(jeecgAuthenticationConvert)));
return http.build();
}
/**
* 数据库保存注册客户端信息
*/
@Bean
public RegisteredClientRepository registeredClientRepository() {
return new JdbcRegisteredClientRepository(jdbcTemplate);
}
/**
*配置 JWK为JWT(id_token)提供加密密钥,用于加密/解密或签名/验签
* JWK详细见https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key-41
*/
@Bean
@SneakyThrows
public JWKSource<SecurityContext> jwkSource() {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
// 如果不设置secureRandom会存在一个问题当应用重启后原有的token将会全部失效因为重启的keyPair与之前已经不同
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
// 重要!生产环境需要修改!
secureRandom.setSeed("jeecg".getBytes());
keyPairGenerator.initialize(256, secureRandom);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
ECKey jwk = new ECKey.Builder(Curve.P_256, publicKey)
.privateKey(privateKey)
.keyID("jeecg")
.build();
JWKSet jwkSet = new JWKSet(jwk);
return new ImmutableJWKSet<>(jwkSet);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
/**
* 配置jwt解析器
*/
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
/**
*配置token生成器
*/
@Bean
OAuth2TokenGenerator<?> tokenGenerator() {
JwtGenerator jwtGenerator = new JwtGenerator(new NimbusJwtEncoder(jwkSource()));
OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator();
OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
return new DelegatingOAuth2TokenGenerator(
new JeecgOAuth2AccessTokenGenerator(new NimbusJwtEncoder(jwkSource())),
new OAuth2RefreshTokenGenerator()
);
}
}

View File

@ -0,0 +1,81 @@
package org.jeecg.config.security.app;
import jakarta.servlet.http.HttpServletRequest;
import org.jeecg.config.security.LoginType;
import org.jeecg.config.security.password.PasswordGrantAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
* APP模式认证转换器
* @author EightMonth
* @date 2024/1/1
*/
public class AppGrantAuthenticationConvert implements AuthenticationConverter {
@Override
public Authentication convert(HttpServletRequest request) {
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
if (!LoginType.APP.equals(grantType)) {
return null;
}
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
//从request中提取请求参数然后存入MultiValueMap<String, String>
MultiValueMap<String, String> parameters = getParameters(request);
// username (REQUIRED)
String username = parameters.getFirst(OAuth2ParameterNames.USERNAME);
if (!StringUtils.hasText(username) ||
parameters.get(OAuth2ParameterNames.USERNAME).size() != 1) {
throw new OAuth2AuthenticationException("无效请求,用户名不能为空!");
}
String password = parameters.getFirst(OAuth2ParameterNames.PASSWORD);
if (!StringUtils.hasText(password) ||
parameters.get(OAuth2ParameterNames.PASSWORD).size() != 1) {
throw new OAuth2AuthenticationException("无效请求,密码不能为空!");
}
//收集要传入PasswordGrantAuthenticationToken构造方法的参数
//该参数接下来在PasswordGrantAuthenticationProvider中使用
Map<String, Object> additionalParameters = new HashMap<>();
//遍历从request中提取的参数排除掉grant_type、client_id、code等字段参数其他参数收集到additionalParameters中
parameters.forEach((key, value) -> {
if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
!key.equals(OAuth2ParameterNames.CLIENT_ID) &&
!key.equals(OAuth2ParameterNames.CODE)) {
additionalParameters.put(key, value.get(0));
}
});
//返回自定义的PasswordGrantAuthenticationToken对象
return new PasswordGrantAuthenticationToken(clientPrincipal, additionalParameters);
}
/**
*从request中提取请求参数然后存入MultiValueMap<String, String>
*/
private static MultiValueMap<String, String> getParameters(HttpServletRequest request) {
Map<String, String[]> parameterMap = request.getParameterMap();
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(parameterMap.size());
parameterMap.forEach((key, values) -> {
if (values.length > 0) {
for (String value : values) {
parameters.add(key, value);
}
}
});
return parameters;
}
}

View File

@ -0,0 +1,318 @@
package org.jeecg.config.security.app;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.exception.JeecgCaptchaException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.system.vo.SysDepartModel;
import org.jeecg.common.util.Md5Util;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.security.password.PasswordGrantAuthenticationToken;
import org.jeecg.modules.base.service.BaseCommonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.*;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.security.Principal;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* APP模式认证处理器负责处理该认证模式下的核心逻辑
* @author EightMonth
* @date 2024/1/1
*/
@Slf4j
public class AppGrantAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
private final OAuth2AuthorizationService authorizationService;
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
@Autowired
private CommonAPI commonAPI;
@Autowired
private RedisUtil redisUtil;
@Autowired
private JeecgBaseConfig jeecgBaseConfig;
@Autowired
private BaseCommonService baseCommonService;
public AppGrantAuthenticationProvider(OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) {
Assert.notNull(authorizationService, "authorizationService cannot be null");
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null");
this.authorizationService = authorizationService;
this.tokenGenerator = tokenGenerator;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
AppGrantAuthenticationToken appGrantAuthenticationToken = (AppGrantAuthenticationToken) authentication;
Map<String, Object> additionalParameter = appGrantAuthenticationToken.getAdditionalParameters();
// 授权类型
AuthorizationGrantType authorizationGrantType = appGrantAuthenticationToken.getGrantType();
// 用户名
String username = (String) additionalParameter.get(OAuth2ParameterNames.USERNAME);
// 密码
String password = (String) additionalParameter.get(OAuth2ParameterNames.PASSWORD);
//请求参数权限范围
String requestScopesStr = (String)additionalParameter.getOrDefault(OAuth2ParameterNames.SCOPE, "*");
//请求参数权限范围专场集合
Set<String> requestScopeSet = Stream.of(requestScopesStr.split(" ")).collect(Collectors.toSet());
// 验证码
String captcha = (String) additionalParameter.get("captcha");
String checkKey = (String) additionalParameter.get("checkKey");
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(appGrantAuthenticationToken);
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
// 检查登录失败次数
if(isLoginFailOvertimes(username)){
Map<String, Object> map = new HashMap<>();
map.put("message", "该用户登录失败次数过多请于10分钟后再次登录");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
if(captcha==null){
Map<String, Object> map = new HashMap<>();
map.put("message", "验证码无效");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
String lowerCaseCaptcha = captcha.toLowerCase();
// 加入密钥作为混淆,避免简单的拼接,被外部利用,用户自定义该密钥即可
String origin = lowerCaseCaptcha+checkKey+jeecgBaseConfig.getSignatureSecret();
String realKey = Md5Util.md5Encode(origin, "utf-8");
Object checkCode = redisUtil.get(realKey);
//当进入登录页时,有一定几率出现验证码错误 #1714
if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
Map<String, Object> map = new HashMap<>();
map.put("message", "验证码错误");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
if (!registeredClient.getAuthorizationGrantTypes().contains(authorizationGrantType)) {
Map<String, Object> map = new HashMap<>();
map.put("message", "非法登录");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
// 通过用户名获取用户信息
LoginUser loginUser = commonAPI.getUserByName(username);
//update-begin---author:eightmonth ---date:2024-04-30 for【6168】master分支切sas分支登录发生错误-----------
if (Objects.isNull(loginUser) || !StringUtils.hasText(loginUser.getSalt())) {
redisUtil.del(CacheConstant.SYS_USERS_CACHE+"::"+username);
loginUser = commonAPI.getUserByName(username);
}
//update-end---author:eightmonth ---date::2024-04-30 for【6168】master分支切sas分支登录发生错误--------------
// 检查用户可行性
checkUserIsEffective(loginUser);
// 不使用spring security passwordEncoder针对密码进行匹配使用自有加密匹配针对 spring security使用noop传输
password = PasswordUtil.encrypt(username, password, loginUser.getSalt());
if (!password.equals(loginUser.getPassword())) {
addLoginFailOvertimes(username);
Map<String, Object> map = new HashMap<>();
map.put("message", "用户名或密码不正确");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
//由于在上面已验证过用户名、密码现在构建一个已认证的对象UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken.authenticated(loginUser,clientPrincipal,new ArrayList<>());
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
.registeredClient(registeredClient)
.principal(usernamePasswordAuthenticationToken)
.authorizationServerContext(AuthorizationServerContextHolder.getContext())
.authorizationGrantType(authorizationGrantType)
.authorizedScopes(requestScopeSet)
.authorizationGrant(appGrantAuthenticationToken);
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
.principalName(clientPrincipal.getName())
.authorizedScopes(requestScopeSet)
.attribute(Principal.class.getName(), username)
.authorizationGrantType(authorizationGrantType);
// ----- Access token -----
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
if (generatedAccessToken == null) {
Map<String, Object> map = new HashMap<>();
map.put("message", "无法生成访问token请联系管理系。");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
if (generatedAccessToken instanceof ClaimAccessor) {
authorizationBuilder.token(accessToken, (metadata) -> {
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims());
});
} else {
authorizationBuilder.accessToken(accessToken);
}
// ----- Refresh token -----
OAuth2RefreshToken refreshToken = null;
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN) &&
// 不向公共客户端颁发刷新令牌
!clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE)) {
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
Map<String, Object> map = new HashMap<>();
map.put("message", "无法生成刷新token请联系管理员。");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
authorizationBuilder.refreshToken(refreshToken);
}
OAuth2Authorization authorization = authorizationBuilder.build();
// 保存认证信息至redis
authorizationService.save(authorization);
// 登录成功删除redis中的验证码
redisUtil.del(realKey);
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
JSONObject addition = new JSONObject(new LinkedHashMap<>());
addition.put("token", accessToken.getTokenValue());
// 设置租户
JSONObject jsonObject = commonAPI.setLoginTenant(username);
addition.putAll(jsonObject.getInnerMap());
// 设置登录用户信息
addition.put("userInfo", loginUser);
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
List<SysDepartModel> departs = commonAPI.queryUserDeparts(loginUser.getId());
addition.put("departs", departs);
if (departs == null || departs.size() == 0) {
addition.put("multi_depart", 0);
} else if (departs.size() == 1) {
commonAPI.updateUserDepart(username, departs.get(0).getOrgCode(),null);
addition.put("multi_depart", 1);
} else {
//查询当前是否有登录部门
if(oConvertUtils.isEmpty(loginUser.getOrgCode())){
commonAPI.updateUserDepart(username, departs.get(0).getOrgCode(),null);
}
addition.put("multi_depart", 2);
}
// 兼容原有shiro登录结果处理
Map<String, Object> map = new HashMap<>();
map.put("result", addition);
map.put("code", 200);
map.put("success", true);
map.put("timestamp", System.currentTimeMillis());
// 返回access_token、refresh_token以及其它信息给到前端
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, map);
}
@Override
public boolean supports(Class<?> authentication) {
return AppGrantAuthenticationToken.class.isAssignableFrom(authentication);
}
private static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
OAuth2ClientAuthenticationToken clientPrincipal = null;
if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
}
if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
return clientPrincipal;
}
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
}
/**
* 登录失败超出次数5 返回true
* @param username
* @return
*/
private boolean isLoginFailOvertimes(String username){
String key = CommonConstant.LOGIN_FAIL + username;
Object failTime = redisUtil.get(key);
if(failTime!=null){
Integer val = Integer.parseInt(failTime.toString());
if(val>5){
return true;
}
}
return false;
}
/**
* 记录登录失败次数
* @param username
*/
private void addLoginFailOvertimes(String username){
String key = CommonConstant.LOGIN_FAIL + username;
Object failTime = redisUtil.get(key);
Integer val = 0;
if(failTime!=null){
val = Integer.parseInt(failTime.toString());
}
// 10分钟
redisUtil.set(key, ++val, 10);
}
/**
* 校验用户是否有效
*/
private void checkUserIsEffective(LoginUser loginUser) {
//情况1根据用户信息查询该用户不存在
if (Objects.isNull(loginUser)) {
baseCommonService.addLog("用户登录失败,用户不存在!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户不存在,请注册");
}
//情况2根据用户信息查询该用户已注销
//update-begin---author:王帅 Date:20200601 forif条件永远为falsebug------------
if (CommonConstant.DEL_FLAG_1.equals(loginUser.getDelFlag())) {
//update-end---author:王帅 Date:20200601 forif条件永远为falsebug------------
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已注销!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户已注销");
}
//情况3根据用户信息查询该用户已冻结
if (CommonConstant.USER_FREEZE.equals(loginUser.getStatus())) {
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已冻结!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户已冻结");
}
}
}

View File

@ -0,0 +1,21 @@
package org.jeecg.config.security.app;
import org.jeecg.config.security.LoginType;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
import java.util.Map;
/**
* APP模式认证专用token类型方法spring authorization server进行认证流转配合convert使用
* @author EightMonth
* @date 2024/1/1
*/
public class AppGrantAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
public AppGrantAuthenticationToken(Authentication clientPrincipal, Map<String, Object> additionalParameters) {
super(new AuthorizationGrantType(LoginType.APP), clientPrincipal, additionalParameters);
}
}

View File

@ -0,0 +1,82 @@
package org.jeecg.config.security.password;
import jakarta.servlet.http.HttpServletRequest;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.config.security.LoginType;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
* 密码模式认证转换器
* @author EightMonth
* @date 2024/1/1
*/
public class PasswordGrantAuthenticationConvert implements AuthenticationConverter {
@Override
public Authentication convert(HttpServletRequest request) {
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
if (!LoginType.PASSWORD.equals(grantType)) {
return null;
}
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
//从request中提取请求参数然后存入MultiValueMap<String, String>
MultiValueMap<String, String> parameters = getParameters(request);
// username (REQUIRED)
String username = parameters.getFirst(OAuth2ParameterNames.USERNAME);
if (!StringUtils.hasText(username) ||
parameters.get(OAuth2ParameterNames.USERNAME).size() != 1) {
throw new OAuth2AuthenticationException("无效请求,用户名不能为空!");
}
String password = parameters.getFirst(OAuth2ParameterNames.PASSWORD);
if (!StringUtils.hasText(password) ||
parameters.get(OAuth2ParameterNames.PASSWORD).size() != 1) {
throw new OAuth2AuthenticationException("无效请求,密码不能为空!");
}
//收集要传入PasswordGrantAuthenticationToken构造方法的参数
//该参数接下来在PasswordGrantAuthenticationProvider中使用
Map<String, Object> additionalParameters = new HashMap<>();
//遍历从request中提取的参数排除掉grant_type、client_id、code等字段参数其他参数收集到additionalParameters中
parameters.forEach((key, value) -> {
if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
!key.equals(OAuth2ParameterNames.CLIENT_ID) &&
!key.equals(OAuth2ParameterNames.CODE)) {
additionalParameters.put(key, value.get(0));
}
});
//返回自定义的PasswordGrantAuthenticationToken对象
return new PasswordGrantAuthenticationToken(clientPrincipal, additionalParameters);
}
/**
*从request中提取请求参数然后存入MultiValueMap<String, String>
*/
private static MultiValueMap<String, String> getParameters(HttpServletRequest request) {
Map<String, String[]> parameterMap = request.getParameterMap();
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(parameterMap.size());
parameterMap.forEach((key, values) -> {
if (values.length > 0) {
for (String value : values) {
parameters.add(key, value);
}
}
});
return parameters;
}
}

View File

@ -0,0 +1,317 @@
package org.jeecg.config.security.password;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.exception.JeecgCaptchaException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.system.vo.SysDepartModel;
import org.jeecg.common.util.Md5Util;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.modules.base.service.BaseCommonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.core.*;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.security.Principal;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 密码模式认证处理器,负责处理该认证模式下的核心逻辑
* @author EightMonth
* @date 2024/1/1
*/
@Slf4j
public class PasswordGrantAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
private final OAuth2AuthorizationService authorizationService;
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
@Autowired
private CommonAPI commonAPI;
@Autowired
private RedisUtil redisUtil;
@Autowired
private JeecgBaseConfig jeecgBaseConfig;
@Autowired
private BaseCommonService baseCommonService;
public PasswordGrantAuthenticationProvider(OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) {
Assert.notNull(authorizationService, "authorizationService cannot be null");
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null");
this.authorizationService = authorizationService;
this.tokenGenerator = tokenGenerator;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
PasswordGrantAuthenticationToken passwordGrantAuthenticationToken = (PasswordGrantAuthenticationToken) authentication;
Map<String, Object> additionalParameter = passwordGrantAuthenticationToken.getAdditionalParameters();
// 授权类型
AuthorizationGrantType authorizationGrantType = passwordGrantAuthenticationToken.getGrantType();
// 用户名
String username = (String) additionalParameter.get(OAuth2ParameterNames.USERNAME);
// 密码
String password = (String) additionalParameter.get(OAuth2ParameterNames.PASSWORD);
//请求参数权限范围
String requestScopesStr = (String)additionalParameter.getOrDefault(OAuth2ParameterNames.SCOPE, "*");
//请求参数权限范围专场集合
Set<String> requestScopeSet = Stream.of(requestScopesStr.split(" ")).collect(Collectors.toSet());
// 验证码
String captcha = (String) additionalParameter.get("captcha");
String checkKey = (String) additionalParameter.get("checkKey");
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(passwordGrantAuthenticationToken);
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
// 检查登录失败次数
if(isLoginFailOvertimes(username)){
throw new JeecgBootException("该用户登录失败次数过多请于10分钟后再次登录");
}
if(captcha==null){
throw new JeecgBootException("验证码无效");
}
String lowerCaseCaptcha = captcha.toLowerCase();
// 加入密钥作为混淆,避免简单的拼接,被外部利用,用户自定义该密钥即可
String origin = lowerCaseCaptcha+checkKey+jeecgBaseConfig.getSignatureSecret();
String realKey = Md5Util.md5Encode(origin, "utf-8");
Object checkCode = redisUtil.get(realKey);
//当进入登录页时,有一定几率出现验证码错误 #1714
if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
Map<String, Object> map = new HashMap<>();
map.put("message", "验证码错误");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
if (!registeredClient.getAuthorizationGrantTypes().contains(authorizationGrantType)) {
Map<String, Object> map = new HashMap<>();
map.put("message", "非法登录");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
// 通过用户名获取用户信息
LoginUser loginUser = commonAPI.getUserByName(username);
//update-begin---author:eightmonth ---date:2024-04-30 for【6168】master分支切sas分支登录发生错误-----------
if (Objects.isNull(loginUser) || !StringUtils.hasText(loginUser.getSalt())) {
redisUtil.del(CacheConstant.SYS_USERS_CACHE+"::"+username);
loginUser = commonAPI.getUserByName(username);
}
//update-end---author:eightmonth ---date::2024-04-30 for【6168】master分支切sas分支登录发生错误--------------
// 检查用户可行性
checkUserIsEffective(loginUser);
// 不使用spring security passwordEncoder针对密码进行匹配使用自有加密匹配针对 spring security使用noop传输
password = PasswordUtil.encrypt(username, password, loginUser.getSalt());
if (!password.equals(loginUser.getPassword())) {
addLoginFailOvertimes(username);
Map<String, Object> map = new HashMap<>();
map.put("message", "用户名或密码不正确");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
//由于在上面已验证过用户名、密码现在构建一个已认证的对象UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken.authenticated(loginUser,clientPrincipal,new ArrayList<>());
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
.registeredClient(registeredClient)
.principal(usernamePasswordAuthenticationToken)
.authorizationServerContext(AuthorizationServerContextHolder.getContext())
.authorizationGrantType(authorizationGrantType)
.authorizedScopes(requestScopeSet)
.authorizationGrant(passwordGrantAuthenticationToken);
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
.principalName(clientPrincipal.getName())
.authorizedScopes(requestScopeSet)
.attribute(Principal.class.getName(), username)
.authorizationGrantType(authorizationGrantType);
// ----- Access token -----
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
if (generatedAccessToken == null) {
Map<String, Object> map = new HashMap<>();
map.put("message", "无法生成访问token请联系管理系。");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
if (generatedAccessToken instanceof ClaimAccessor) {
authorizationBuilder.token(accessToken, (metadata) -> {
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims());
});
} else {
authorizationBuilder.accessToken(accessToken);
}
// ----- Refresh token -----
OAuth2RefreshToken refreshToken = null;
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN) &&
// 不向公共客户端颁发刷新令牌
!clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE)) {
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
Map<String, Object> map = new HashMap<>();
map.put("message", "无法生成访问token请联系管理系。");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
authorizationBuilder.refreshToken(refreshToken);
}
OAuth2Authorization authorization = authorizationBuilder.build();
// 保存认证信息至redis
authorizationService.save(authorization);
// 登录成功删除redis中的验证码
redisUtil.del(realKey);
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
JSONObject addition = new JSONObject(new LinkedHashMap<>());
addition.put("token", accessToken.getTokenValue());
// 设置租户
JSONObject jsonObject = commonAPI.setLoginTenant(username);
addition.putAll(jsonObject.getInnerMap());
// 设置登录用户信息
addition.put("userInfo", loginUser);
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
List<SysDepartModel> departs = commonAPI.queryUserDeparts(loginUser.getId());
addition.put("departs", departs);
if (departs == null || departs.size() == 0) {
addition.put("multi_depart", 0);
} else if (departs.size() == 1) {
commonAPI.updateUserDepart(username, departs.get(0).getOrgCode(),null);
addition.put("multi_depart", 1);
} else {
//查询当前是否有登录部门
if(oConvertUtils.isEmpty(loginUser.getOrgCode())){
commonAPI.updateUserDepart(username, departs.get(0).getOrgCode(),null);
}
addition.put("multi_depart", 2);
}
// 兼容原有shiro登录结果处理
Map<String, Object> map = new HashMap<>();
map.put("result", addition);
map.put("code", 200);
map.put("success", true);
map.put("timestamp", System.currentTimeMillis());
// 返回access_token、refresh_token以及其它信息给到前端
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, map);
}
@Override
public boolean supports(Class<?> authentication) {
return PasswordGrantAuthenticationToken.class.isAssignableFrom(authentication);
}
private static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
OAuth2ClientAuthenticationToken clientPrincipal = null;
if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
}
if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
return clientPrincipal;
}
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
}
/**
* 登录失败超出次数5 返回true
* @param username
* @return
*/
private boolean isLoginFailOvertimes(String username){
String key = CommonConstant.LOGIN_FAIL + username;
Object failTime = redisUtil.get(key);
if(failTime!=null){
Integer val = Integer.parseInt(failTime.toString());
if(val>5){
return true;
}
}
return false;
}
/**
* 记录登录失败次数
* @param username
*/
private void addLoginFailOvertimes(String username){
String key = CommonConstant.LOGIN_FAIL + username;
Object failTime = redisUtil.get(key);
Integer val = 0;
if(failTime!=null){
val = Integer.parseInt(failTime.toString());
}
// 10分钟
redisUtil.set(key, ++val, 10);
}
/**
* 校验用户是否有效
*/
private void checkUserIsEffective(LoginUser loginUser) {
//情况1根据用户信息查询该用户不存在
if (Objects.isNull(loginUser)) {
baseCommonService.addLog("用户登录失败,用户不存在!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户不存在,请注册");
}
//情况2根据用户信息查询该用户已注销
//update-begin---author:王帅 Date:20200601 forif条件永远为falsebug------------
if (CommonConstant.DEL_FLAG_1.equals(loginUser.getDelFlag())) {
//update-end---author:王帅 Date:20200601 forif条件永远为falsebug------------
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已注销!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户已注销");
}
//情况3根据用户信息查询该用户已冻结
if (CommonConstant.USER_FREEZE.equals(loginUser.getStatus())) {
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已冻结!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户已冻结");
}
}
}

View File

@ -0,0 +1,21 @@
package org.jeecg.config.security.password;
import org.jeecg.config.security.LoginType;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
import java.util.Map;
/**
* 密码模式认证专用token类型方法spring authorization server进行认证流转配合convert使用
* @author EightMonth
* @date 2024/1/1
*/
public class PasswordGrantAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
public PasswordGrantAuthenticationToken(Authentication clientPrincipal, Map<String, Object> additionalParameters) {
super(new AuthorizationGrantType(LoginType.PASSWORD), clientPrincipal, additionalParameters);
}
}

View File

@ -0,0 +1,77 @@
package org.jeecg.config.security.phone;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import org.jeecg.config.security.LoginType;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
* 手机号模式认证转换器
* @author EightMonth
* @date 2024/1/1
*/
@AllArgsConstructor
public class PhoneGrantAuthenticationConvert implements AuthenticationConverter {
@Override
public Authentication convert(HttpServletRequest request) {
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
if (!LoginType.PHONE.equals(grantType)) {
return null;
}
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
//从request中提取请求参数然后存入MultiValueMap<String, String>
MultiValueMap<String, String> parameters = getParameters(request);
// 验证码
String captcha = parameters.getFirst("captcha");
if (!StringUtils.hasText(captcha)) {
throw new OAuth2AuthenticationException("无效请求,验证码不能为空!");
}
//收集要传入PhoneGrantAuthenticationToken构造方法的参数
//该参数接下来在PhoneGrantAuthenticationProvider中使用
Map<String, Object> additionalParameters = new HashMap<>();
//遍历从request中提取的参数排除掉grant_type、client_id、code等字段参数其他参数收集到additionalParameters中
parameters.forEach((key, value) -> {
if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
!key.equals(OAuth2ParameterNames.CLIENT_ID) &&
!key.equals(OAuth2ParameterNames.CODE)) {
additionalParameters.put(key, value.get(0));
}
});
//返回自定义的PhoneGrantAuthenticationToken对象
return new PhoneGrantAuthenticationToken(clientPrincipal, additionalParameters);
}
/**
*从request中提取请求参数然后存入MultiValueMap<String, String>
*/
private static MultiValueMap<String, String> getParameters(HttpServletRequest request) {
Map<String, String[]> parameterMap = request.getParameterMap();
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(parameterMap.size());
parameterMap.forEach((key, values) -> {
if (values.length > 0) {
for (String value : values) {
parameters.add(key, value);
}
}
});
return parameters;
}
}

View File

@ -0,0 +1,290 @@
package org.jeecg.config.security.phone;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.exception.JeecgCaptchaException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.system.vo.SysDepartModel;
import org.jeecg.common.util.Md5Util;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.security.password.PasswordGrantAuthenticationToken;
import org.jeecg.modules.base.service.BaseCommonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.*;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
import org.springframework.util.Assert;
import java.security.Principal;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 手机号模式认证处理器,负责处理该认证模式下的核心逻辑
* @author EightMonth
* @date 2024/1/1
*/
@Slf4j
public class PhoneGrantAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
private final OAuth2AuthorizationService authorizationService;
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
@Autowired
private CommonAPI commonAPI;
@Autowired
private RedisUtil redisUtil;
@Autowired
private JeecgBaseConfig jeecgBaseConfig;
@Autowired
private BaseCommonService baseCommonService;
public PhoneGrantAuthenticationProvider(OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) {
Assert.notNull(authorizationService, "authorizationService cannot be null");
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null");
this.authorizationService = authorizationService;
this.tokenGenerator = tokenGenerator;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
PhoneGrantAuthenticationToken phoneGrantAuthenticationToken = (PhoneGrantAuthenticationToken) authentication;
Map<String, Object> additionalParameter = phoneGrantAuthenticationToken.getAdditionalParameters();
// 授权类型
AuthorizationGrantType authorizationGrantType = phoneGrantAuthenticationToken.getGrantType();
// 手机号
String phone = (String) additionalParameter.get("mobile");
if(isLoginFailOvertimes(phone)){
throw new JeecgBootException("该用户登录失败次数过多请于10分钟后再次登录");
}
//请求参数权限范围
String requestScopesStr = (String)additionalParameter.getOrDefault(OAuth2ParameterNames.SCOPE, "*");
//请求参数权限范围专场集合
Set<String> requestScopeSet = Stream.of(requestScopesStr.split(" ")).collect(Collectors.toSet());
// 验证码
String captcha = (String) additionalParameter.get("captcha");
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(phoneGrantAuthenticationToken);
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
// 通过手机号获取用户信息
LoginUser loginUser = commonAPI.getUserByPhone(phone);
// 检查用户可行性
checkUserIsEffective(loginUser);
String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+phone;
Object code = redisUtil.get(redisKey);
if (!captcha.equals(code)) {
//update-begin-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
addLoginFailOvertimes(phone);
Map<String, Object> map = new HashMap<>();
map.put("message", "手机验证码错误");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
if (!registeredClient.getAuthorizationGrantTypes().contains(authorizationGrantType)) {
Map<String, Object> map = new HashMap<>();
map.put("message", "非法登录");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
//由于在上面已验证过用户名、密码现在构建一个已认证的对象UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken.authenticated(loginUser,clientPrincipal,new ArrayList<>());
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
.registeredClient(registeredClient)
.principal(usernamePasswordAuthenticationToken)
.authorizationServerContext(AuthorizationServerContextHolder.getContext())
.authorizationGrantType(authorizationGrantType)
.authorizedScopes(requestScopeSet)
.authorizationGrant(phoneGrantAuthenticationToken);
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
.principalName(clientPrincipal.getName())
.authorizedScopes(requestScopeSet)
.attribute(Principal.class.getName(), loginUser.getUsername())
.authorizationGrantType(authorizationGrantType);
// ----- Access token -----
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
if (generatedAccessToken == null) {
Map<String, Object> map = new HashMap<>();
map.put("message", "无法生成刷新token请联系管理员。");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
if (generatedAccessToken instanceof ClaimAccessor) {
authorizationBuilder.token(accessToken, (metadata) -> {
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims());
});
} else {
authorizationBuilder.accessToken(accessToken);
}
// ----- Refresh token -----
OAuth2RefreshToken refreshToken = null;
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN) &&
// 不向公共客户端颁发刷新令牌
!clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE)) {
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
Map<String, Object> map = new HashMap<>();
map.put("message", "无法生成刷新token请联系管理员。");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
authorizationBuilder.refreshToken(refreshToken);
}
OAuth2Authorization authorization = authorizationBuilder.build();
// 保存认证信息至redis
authorizationService.save(authorization);
baseCommonService.addLog("用户名: " + loginUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
JSONObject addition = new JSONObject(new LinkedHashMap<>());
addition.put("token", accessToken.getTokenValue());
// 设置租户
JSONObject jsonObject = commonAPI.setLoginTenant(loginUser.getUsername());
addition.putAll(jsonObject.getInnerMap());
// 设置登录用户信息
addition.put("userInfo", loginUser);
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
List<SysDepartModel> departs = commonAPI.queryUserDeparts(loginUser.getId());
addition.put("departs", departs);
if (departs == null || departs.size() == 0) {
addition.put("multi_depart", 0);
} else if (departs.size() == 1) {
commonAPI.updateUserDepart(loginUser.getUsername(), departs.get(0).getOrgCode(),null);
addition.put("multi_depart", 1);
} else {
//查询当前是否有登录部门
if(oConvertUtils.isEmpty(loginUser.getOrgCode())){
commonAPI.updateUserDepart(loginUser.getUsername(), departs.get(0).getOrgCode(),null);
}
addition.put("multi_depart", 2);
}
// 兼容原有shiro登录结果处理
Map<String, Object> map = new HashMap<>();
map.put("result", addition);
map.put("code", 200);
map.put("success", true);
map.put("timestamp", System.currentTimeMillis());
// 返回access_token、refresh_token以及其它信息给到前端
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, map);
}
@Override
public boolean supports(Class<?> authentication) {
return PhoneGrantAuthenticationToken.class.isAssignableFrom(authentication);
}
private static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
OAuth2ClientAuthenticationToken clientPrincipal = null;
if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
}
if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
return clientPrincipal;
}
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
}
/**
* 登录失败超出次数5 返回true
* @param username
* @return
*/
private boolean isLoginFailOvertimes(String username){
String key = CommonConstant.LOGIN_FAIL + username;
Object failTime = redisUtil.get(key);
if(failTime!=null){
Integer val = Integer.parseInt(failTime.toString());
if(val>5){
return true;
}
}
return false;
}
/**
* 记录登录失败次数
* @param username
*/
private void addLoginFailOvertimes(String username){
String key = CommonConstant.LOGIN_FAIL + username;
Object failTime = redisUtil.get(key);
Integer val = 0;
if(failTime!=null){
val = Integer.parseInt(failTime.toString());
}
// 10分钟
redisUtil.set(key, ++val, 10);
}
/**
* 校验用户是否有效
*/
private void checkUserIsEffective(LoginUser loginUser) {
//情况1根据用户信息查询该用户不存在
if (Objects.isNull(loginUser)) {
baseCommonService.addLog("用户登录失败,用户不存在!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户不存在,请注册");
}
//情况2根据用户信息查询该用户已注销
//update-begin---author:王帅 Date:20200601 forif条件永远为falsebug------------
if (CommonConstant.DEL_FLAG_1.equals(loginUser.getDelFlag())) {
//update-end---author:王帅 Date:20200601 forif条件永远为falsebug------------
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已注销!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户已注销");
}
//情况3根据用户信息查询该用户已冻结
if (CommonConstant.USER_FREEZE.equals(loginUser.getStatus())) {
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已冻结!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户已冻结");
}
}
}

View File

@ -0,0 +1,21 @@
package org.jeecg.config.security.phone;
import org.jeecg.config.security.LoginType;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
import java.util.Map;
/**
* 手机号模式认证专用token类型方法spring authorization server进行认证流转配合convert使用
* @author EightMonth
* @date 2024/1/1
*/
public class PhoneGrantAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
public PhoneGrantAuthenticationToken(Authentication clientPrincipal, Map<String, Object> additionalParameters) {
super(new AuthorizationGrantType(LoginType.PHONE), clientPrincipal, additionalParameters);
}
}

View File

@ -0,0 +1,188 @@
package org.jeecg.config.security.self;
import com.alibaba.fastjson.JSONObject;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBoot401Exception;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.system.vo.SysDepartModel;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.modules.base.service.BaseCommonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.*;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.security.Principal;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 自用生成token处理器不对外开放外部请求无法通过该方式生成token
* @author eightmonth@qq.com
* @date 2024/3/19 11:40
*/
@Component
public class SelfAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
private final OAuth2AuthorizationService authorizationService;
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
@Autowired
private CommonAPI commonAPI;
@Autowired
private RedisUtil redisUtil;
@Autowired
private JeecgBaseConfig jeecgBaseConfig;
@Autowired
private BaseCommonService baseCommonService;
public SelfAuthenticationProvider(OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) {
Assert.notNull(authorizationService, "authorizationService cannot be null");
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null");
this.authorizationService = authorizationService;
this.tokenGenerator = tokenGenerator;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
SelfAuthenticationToken passwordGrantAuthenticationToken = (SelfAuthenticationToken) authentication;
Map<String, Object> additionalParameter = passwordGrantAuthenticationToken.getAdditionalParameters();
// 授权类型
AuthorizationGrantType authorizationGrantType = passwordGrantAuthenticationToken.getGrantType();
// 用户名
String username = (String) additionalParameter.get(OAuth2ParameterNames.USERNAME);
//请求参数权限范围
String requestScopesStr = "*";
//请求参数权限范围专场集合
Set<String> requestScopeSet = Stream.of(requestScopesStr.split(" ")).collect(Collectors.toSet());
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(passwordGrantAuthenticationToken);
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
// 通过用户名获取用户信息
// LoginUser loginUser = commonAPI.getUserByName(username);
// 检查用户可行性
// checkUserIsEffective(loginUser);
//由于在上面已验证过用户名、密码现在构建一个已认证的对象UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken.authenticated(username,clientPrincipal,new ArrayList<>());
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
.registeredClient(registeredClient)
.principal(usernamePasswordAuthenticationToken)
.authorizationGrantType(authorizationGrantType)
.authorizedScopes(requestScopeSet)
.authorizationGrant(passwordGrantAuthenticationToken);
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
.principalName(clientPrincipal.getName())
.authorizedScopes(requestScopeSet)
.attribute(Principal.class.getName(), username)
.authorizationGrantType(authorizationGrantType);
// ----- Access token -----
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
if (generatedAccessToken == null) {
throw new JeecgBoot401Exception("无法生成刷新token请联系管理员。");
}
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
if (generatedAccessToken instanceof ClaimAccessor) {
authorizationBuilder.token(accessToken, (metadata) -> {
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims());
});
} else {
authorizationBuilder.accessToken(accessToken);
}
// ----- Refresh token -----
OAuth2RefreshToken refreshToken = null;
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN) &&
// 不向公共客户端颁发刷新令牌
!clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE)) {
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
Map<String, Object> map = new HashMap<>();
map.put("message", "无法生成刷新token请联系管理员。");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
authorizationBuilder.refreshToken(refreshToken);
}
OAuth2Authorization authorization = authorizationBuilder.build();
// 保存认证信息至redis
authorizationService.save(authorization);
// 返回access_token、refresh_token以及其它信息给到前端
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken);
}
@Override
public boolean supports(Class<?> authentication) {
return SelfAuthenticationToken.class.isAssignableFrom(authentication);
}
private static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
OAuth2ClientAuthenticationToken clientPrincipal = null;
if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
}
if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
return clientPrincipal;
}
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
}
/**
* 校验用户是否有效
*/
private void checkUserIsEffective(LoginUser loginUser) {
//情况1根据用户信息查询该用户不存在
if (Objects.isNull(loginUser)) {
baseCommonService.addLog("用户登录失败,用户不存在!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户不存在,请注册");
}
//情况2根据用户信息查询该用户已注销
//update-begin---author:王帅 Date:20200601 forif条件永远为falsebug------------
if (CommonConstant.DEL_FLAG_1.equals(loginUser.getDelFlag())) {
//update-end---author:王帅 Date:20200601 forif条件永远为falsebug------------
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已注销!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户已注销");
}
//情况3根据用户信息查询该用户已冻结
if (CommonConstant.USER_FREEZE.equals(loginUser.getStatus())) {
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已冻结!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户已冻结");
}
}
}

View File

@ -0,0 +1,19 @@
package org.jeecg.config.security.self;
import org.jeecg.config.security.LoginType;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
import java.util.Map;
/**
* 自用生成token不支持对外请求仅为程序内部生成token
* @author eightmonth
* @date 2024/3/19 11:37
*/
public class SelfAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
public SelfAuthenticationToken(Authentication clientPrincipal, Map<String, Object> additionalParameters) {
super(new AuthorizationGrantType(LoginType.SELF), clientPrincipal, additionalParameters);
}
}

View File

@ -0,0 +1,81 @@
package org.jeecg.config.security.social;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import org.jeecg.config.security.LoginType;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
* 社交模式认证转换器配合github、企业微信、钉钉、微信登录使用
* @author EightMonth
* @date 2024/1/1
*/
@AllArgsConstructor
public class SocialGrantAuthenticationConvert implements AuthenticationConverter {
@Override
public Authentication convert(HttpServletRequest request) {
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
if (!LoginType.SOCIAL.equals(grantType)) {
return null;
}
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
//从request中提取请求参数然后存入MultiValueMap<String, String>
MultiValueMap<String, String> parameters = getParameters(request);
String token = parameters.getFirst("token");
if (!StringUtils.hasText(token)) {
throw new OAuth2AuthenticationException("无效请求三方token不能为空");
}
String source = parameters.getFirst("thirdType");
if (!StringUtils.hasText(source)) {
throw new OAuth2AuthenticationException("无效请求,三方来源不能为空!");
}
//收集要传入PhoneGrantAuthenticationToken构造方法的参数
//该参数接下来在PhoneGrantAuthenticationProvider中使用
Map<String, Object> additionalParameters = new HashMap<>();
//遍历从request中提取的参数排除掉grant_type、client_id、code等字段参数其他参数收集到additionalParameters中
parameters.forEach((key, value) -> {
if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
!key.equals(OAuth2ParameterNames.CLIENT_ID) &&
!key.equals(OAuth2ParameterNames.CODE)) {
additionalParameters.put(key, value.get(0));
}
});
//返回自定义的PhoneGrantAuthenticationToken对象
return new SocialGrantAuthenticationToken(clientPrincipal, additionalParameters);
}
/**
*从request中提取请求参数然后存入MultiValueMap<String, String>
*/
private static MultiValueMap<String, String> getParameters(HttpServletRequest request) {
Map<String, String[]> parameterMap = request.getParameterMap();
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(parameterMap.size());
parameterMap.forEach((key, values) -> {
if (values.length > 0) {
for (String value : values) {
parameters.add(key, value);
}
}
});
return parameters;
}
}

View File

@ -0,0 +1,276 @@
package org.jeecg.config.security.social;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.system.vo.SysDepartModel;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.security.password.PasswordGrantAuthenticationToken;
import org.jeecg.modules.base.service.BaseCommonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.*;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
import org.springframework.util.Assert;
import java.security.Principal;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 社交模式认证处理器负责处理该认证模式下的核心逻辑配合github、企业微信、钉钉、微信登录使用
* @author EightMonth
* @date 2024/1/1
*/
@Slf4j
public class SocialGrantAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
private final OAuth2AuthorizationService authorizationService;
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
@Autowired
private CommonAPI commonAPI;
@Autowired
private RedisUtil redisUtil;
@Autowired
private JeecgBaseConfig jeecgBaseConfig;
@Autowired
private BaseCommonService baseCommonService;
public SocialGrantAuthenticationProvider(OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) {
Assert.notNull(authorizationService, "authorizationService cannot be null");
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null");
this.authorizationService = authorizationService;
this.tokenGenerator = tokenGenerator;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
SocialGrantAuthenticationToken socialGrantAuthenticationToken = (SocialGrantAuthenticationToken) authentication;
Map<String, Object> additionalParameter = socialGrantAuthenticationToken.getAdditionalParameters();
// 授权类型
AuthorizationGrantType authorizationGrantType = socialGrantAuthenticationToken.getGrantType();
// 三方token
String token = (String) additionalParameter.get("token");
// 三方来源
String source = (String) additionalParameter.get("thirdType");
//请求参数权限范围
String requestScopesStr = (String)additionalParameter.getOrDefault(OAuth2ParameterNames.SCOPE, "*");
//请求参数权限范围专场集合
Set<String> requestScopeSet = Stream.of(requestScopesStr.split(" ")).collect(Collectors.toSet());
DecodedJWT jwt = JWT.decode(token);
String username = jwt.getClaim("username").asString();
// 通过手机号获取用户信息
LoginUser loginUser = commonAPI.getUserByName(username);
// 检查用户可行性
checkUserIsEffective(loginUser);
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(socialGrantAuthenticationToken);
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
if (!registeredClient.getAuthorizationGrantTypes().contains(authorizationGrantType)) {
Map<String, Object> map = new HashMap<>();
map.put("message", "非法登录");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
//由于在上面已验证过用户名、密码现在构建一个已认证的对象UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken.authenticated(loginUser,clientPrincipal,new ArrayList<>());
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
.registeredClient(registeredClient)
.principal(usernamePasswordAuthenticationToken)
.authorizationServerContext(AuthorizationServerContextHolder.getContext())
.authorizationGrantType(authorizationGrantType)
.authorizedScopes(requestScopeSet)
.authorizationGrant(socialGrantAuthenticationToken);
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
.principalName(clientPrincipal.getName())
.authorizedScopes(requestScopeSet)
.attribute(Principal.class.getName(), loginUser.getUsername())
.authorizationGrantType(authorizationGrantType);
// ----- Access token -----
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
if (generatedAccessToken == null) {
Map<String, Object> map = new HashMap<>();
map.put("message", "无法生成访问token请联系管理系。");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
if (generatedAccessToken instanceof ClaimAccessor) {
authorizationBuilder.token(accessToken, (metadata) -> {
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims());
});
} else {
authorizationBuilder.accessToken(accessToken);
}
// ----- Refresh token -----
OAuth2RefreshToken refreshToken = null;
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN) &&
// 不向公共客户端颁发刷新令牌
!clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE)) {
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
Map<String, Object> map = new HashMap<>();
map.put("message", "无法生成刷新token请联系管理员。");
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,"fdsafas", Instant.now(), Instant.now().plusNanos(1)), null, map);
}
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
authorizationBuilder.refreshToken(refreshToken);
}
OAuth2Authorization authorization = authorizationBuilder.build();
// 保存认证信息至redis
authorizationService.save(authorization);
baseCommonService.addLog("用户名: " + loginUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
JSONObject addition = new JSONObject(new LinkedHashMap<>());
addition.put("token", accessToken.getTokenValue());
// 设置租户
JSONObject jsonObject = commonAPI.setLoginTenant(loginUser.getUsername());
addition.putAll(jsonObject.getInnerMap());
// 设置登录用户信息
addition.put("userInfo", loginUser);
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
List<SysDepartModel> departs = commonAPI.queryUserDeparts(loginUser.getId());
addition.put("departs", departs);
if (departs == null || departs.size() == 0) {
addition.put("multi_depart", 0);
} else if (departs.size() == 1) {
commonAPI.updateUserDepart(loginUser.getUsername(), departs.get(0).getOrgCode(),null);
addition.put("multi_depart", 1);
} else {
//查询当前是否有登录部门
if(oConvertUtils.isEmpty(loginUser.getOrgCode())){
commonAPI.updateUserDepart(loginUser.getUsername(), departs.get(0).getOrgCode(),null);
}
addition.put("multi_depart", 2);
}
// 兼容原有shiro登录结果处理
Map<String, Object> map = new HashMap<>();
map.put("result", addition);
map.put("code", 200);
map.put("success", true);
map.put("timestamp", System.currentTimeMillis());
// 返回access_token、refresh_token以及其它信息给到前端
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, map);
}
@Override
public boolean supports(Class<?> authentication) {
return SocialGrantAuthenticationToken.class.isAssignableFrom(authentication);
}
private static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
OAuth2ClientAuthenticationToken clientPrincipal = null;
if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
}
if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
return clientPrincipal;
}
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
}
/**
* 登录失败超出次数5 返回true
* @param username
* @return
*/
private boolean isLoginFailOvertimes(String username){
String key = CommonConstant.LOGIN_FAIL + username;
Object failTime = redisUtil.get(key);
if(failTime!=null){
Integer val = Integer.parseInt(failTime.toString());
if(val>5){
return true;
}
}
return false;
}
/**
* 记录登录失败次数
* @param username
*/
private void addLoginFailOvertimes(String username){
String key = CommonConstant.LOGIN_FAIL + username;
Object failTime = redisUtil.get(key);
Integer val = 0;
if(failTime!=null){
val = Integer.parseInt(failTime.toString());
}
// 10分钟
redisUtil.set(key, ++val, 10);
}
/**
* 校验用户是否有效
*/
private void checkUserIsEffective(LoginUser loginUser) {
//情况1根据用户信息查询该用户不存在
if (Objects.isNull(loginUser)) {
baseCommonService.addLog("用户登录失败,用户不存在!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户不存在,请注册");
}
//情况2根据用户信息查询该用户已注销
//update-begin---author:王帅 Date:20200601 forif条件永远为falsebug------------
if (CommonConstant.DEL_FLAG_1.equals(loginUser.getDelFlag())) {
//update-end---author:王帅 Date:20200601 forif条件永远为falsebug------------
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已注销!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户已注销");
}
//情况3根据用户信息查询该用户已冻结
if (CommonConstant.USER_FREEZE.equals(loginUser.getStatus())) {
baseCommonService.addLog("用户登录失败,用户名:" + loginUser.getUsername() + "已冻结!", CommonConstant.LOG_TYPE_1, null);
throw new JeecgBootException("该用户已冻结");
}
}
}

View File

@ -0,0 +1,21 @@
package org.jeecg.config.security.social;
import org.jeecg.config.security.LoginType;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
import java.util.Map;
/**
* 社交模式认证专用token类型方法spring authorization server进行认证流转配合convert使用配合github、企业微信、钉钉、微信登录使用
* @author EightMonth
* @date 2024/1/1
*/
public class SocialGrantAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
public SocialGrantAuthenticationToken(Authentication clientPrincipal, Map<String, Object> additionalParameters) {
super(new AuthorizationGrantType(LoginType.SOCIAL), clientPrincipal, additionalParameters);
}
}

View File

@ -0,0 +1,23 @@
package org.jeecg.config.security.utils;
import com.alibaba.fastjson2.JSONObject;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.SpringContextUtils;
import org.springframework.security.core.context.SecurityContextHolder;
/**
* 认证信息工具类
* @author EightMonth
* @date 2024/1/10 17:03
*/
public class SecureUtil {
/**
* 通过当前认证信息获取用户信息
* @return
*/
public static LoginUser currentUser() {
String name = SecurityContextHolder.getContext().getAuthentication().getName();
return JSONObject.parseObject(name, LoginUser.class);
}
}

View File

@ -1,28 +0,0 @@
package org.jeecg.config.shiro;
import org.apache.shiro.authc.AuthenticationToken;
/**
* @Author Scott
* @create 2018-07-12 15:19
* @desc
**/
public class JwtToken implements AuthenticationToken {
private static final long serialVersionUID = 1L;
private String token;
public JwtToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}

View File

@ -1,345 +0,0 @@
package org.jeecg.config.shiro;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.*;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean;
import org.jeecg.config.shiro.filters.JwtFilter;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.Environment;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.filter.DelegatingFilterProxy;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import jakarta.annotation.Resource;
import jakarta.servlet.Filter;
import jakarta.servlet.DispatcherType;
import java.lang.reflect.Method;
import java.util.*;
/**
* @author: Scott
* @date: 2018/2/7
* @description: shiro 配置类
*/
@Slf4j
@Configuration
public class ShiroConfig {
@Resource
private LettuceConnectionFactory lettuceConnectionFactory;
@Autowired
private Environment env;
@Resource
private JeecgBaseConfig jeecgBaseConfig;
@Autowired(required = false)
private RedisProperties redisProperties;
/**
* Filter Chain定义说明
*
* 1、一个URL可以配置多个Filter使用逗号分隔
* 2、当设置多个过滤器时全部验证通过才视为通过
* 3、部分过滤器可指定参数如permsroles
*/
@Bean("shiroFilterFactoryBean")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
CustomShiroFilterFactoryBean shiroFilterFactoryBean = new CustomShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 拦截器
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
//支持yml方式配置拦截排除
if(jeecgBaseConfig!=null && jeecgBaseConfig.getShiro()!=null){
String shiroExcludeUrls = jeecgBaseConfig.getShiro().getExcludeUrls();
if(oConvertUtils.isNotEmpty(shiroExcludeUrls)){
String[] permissionUrl = shiroExcludeUrls.split(",");
for(String url : permissionUrl){
filterChainDefinitionMap.put(url,"anon");
}
}
}
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/sys/cas/client/validateLogin", "anon"); //cas验证登录
filterChainDefinitionMap.put("/sys/randomImage/**", "anon"); //登录验证码接口排除
filterChainDefinitionMap.put("/sys/checkCaptcha", "anon"); //登录验证码接口排除
filterChainDefinitionMap.put("/sys/smsCheckCaptcha", "anon"); //短信次数发送太多验证码排除
filterChainDefinitionMap.put("/sys/login", "anon"); //登录接口排除
filterChainDefinitionMap.put("/sys/mLogin", "anon"); //登录接口排除
filterChainDefinitionMap.put("/sys/logout", "anon"); //登出接口排除
filterChainDefinitionMap.put("/sys/thirdLogin/**", "anon"); //第三方登录
filterChainDefinitionMap.put("/sys/getEncryptedString", "anon"); //获取加密串
filterChainDefinitionMap.put("/sys/sms", "anon");//短信验证码
filterChainDefinitionMap.put("/sys/phoneLogin", "anon");//手机登录
filterChainDefinitionMap.put("/sys/user/checkOnlyUser", "anon");//校验用户是否存在
filterChainDefinitionMap.put("/sys/user/register", "anon");//用户注册
filterChainDefinitionMap.put("/sys/user/phoneVerification", "anon");//用户忘记密码验证手机号
filterChainDefinitionMap.put("/sys/user/passwordChange", "anon");//用户更改密码
filterChainDefinitionMap.put("/auth/2step-code", "anon");//登录验证码
filterChainDefinitionMap.put("/sys/common/static/**", "anon");//图片预览 &下载文件不限制token
filterChainDefinitionMap.put("/sys/common/pdf/**", "anon");//pdf预览
//filterChainDefinitionMap.put("/sys/common/view/**", "anon");//图片预览不限制token
//filterChainDefinitionMap.put("/sys/common/download/**", "anon");//文件下载不限制token
filterChainDefinitionMap.put("/generic/**", "anon");//pdf预览需要文件
filterChainDefinitionMap.put("/sys/getLoginQrcode/**", "anon"); //登录二维码
filterChainDefinitionMap.put("/sys/getQrcodeToken/**", "anon"); //监听扫码
filterChainDefinitionMap.put("/sys/checkAuth", "anon"); //授权接口排除
//update-begin--Author:scott Date:20221116 for排除静态资源后缀
filterChainDefinitionMap.put("/", "anon");
filterChainDefinitionMap.put("/doc.html", "anon");
filterChainDefinitionMap.put("/**/*.js", "anon");
filterChainDefinitionMap.put("/**/*.css", "anon");
filterChainDefinitionMap.put("/**/*.html", "anon");
filterChainDefinitionMap.put("/**/*.svg", "anon");
filterChainDefinitionMap.put("/**/*.pdf", "anon");
filterChainDefinitionMap.put("/**/*.jpg", "anon");
filterChainDefinitionMap.put("/**/*.png", "anon");
filterChainDefinitionMap.put("/**/*.gif", "anon");
filterChainDefinitionMap.put("/**/*.ico", "anon");
filterChainDefinitionMap.put("/**/*.ttf", "anon");
filterChainDefinitionMap.put("/**/*.woff", "anon");
filterChainDefinitionMap.put("/**/*.woff2", "anon");
//update-end--Author:scott Date:20221116 for排除静态资源后缀
filterChainDefinitionMap.put("/druid/**", "anon");
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
filterChainDefinitionMap.put("/swagger**/**", "anon");
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/v3/**", "anon");
// update-begin--Author:sunjianlei Date:20210510 for排除消息通告查看详情页面用于第三方APP
filterChainDefinitionMap.put("/sys/annountCement/show/**", "anon");
// update-end--Author:sunjianlei Date:20210510 for排除消息通告查看详情页面用于第三方APP
//积木报表排除
filterChainDefinitionMap.put("/jmreport/**", "anon");
filterChainDefinitionMap.put("/**/*.js.map", "anon");
filterChainDefinitionMap.put("/**/*.css.map", "anon");
//拖拽仪表盘设计器排除
filterChainDefinitionMap.put("/drag/view", "anon");
filterChainDefinitionMap.put("/drag/page/queryById", "anon");
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getAllChartData", "anon");
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getTotalData", "anon");
filterChainDefinitionMap.put("/drag/mock/json/**", "anon");
//大屏模板例子
filterChainDefinitionMap.put("/test/bigScreen/**", "anon");
filterChainDefinitionMap.put("/bigscreen/template1/**", "anon");
filterChainDefinitionMap.put("/bigscreen/template2/**", "anon");
//filterChainDefinitionMap.put("/test/jeecgDemo/rabbitMqClientTest/**", "anon"); //MQ测试
//filterChainDefinitionMap.put("/test/jeecgDemo/html", "anon"); //模板页面
//filterChainDefinitionMap.put("/test/jeecgDemo/redis/**", "anon"); //redis测试
//websocket排除
filterChainDefinitionMap.put("/websocket/**", "anon");//系统通知和公告
filterChainDefinitionMap.put("/newsWebsocket/**", "anon");//CMS模块
filterChainDefinitionMap.put("/vxeSocket/**", "anon");//JVxeTable无痕刷新示例
//性能监控——安全隐患泄露TOEKNdurid连接池也有
//filterChainDefinitionMap.put("/actuator/**", "anon");
//测试模块排除
filterChainDefinitionMap.put("/test/seata/**", "anon");
//错误路径排除
filterChainDefinitionMap.put("/error", "anon");
// 企业微信证书排除
filterChainDefinitionMap.put("/WW_verify*", "anon");
// 添加自己的过滤器并且取名为jwt
Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
//如果cloudServer为空 则说明是单体 需要加载跨域配置【微服务跨域切换】
Object cloudServer = env.getProperty(CommonConstant.CLOUD_SERVER_KEY);
filterMap.put("jwt", new JwtFilter(cloudServer==null));
shiroFilterFactoryBean.setFilters(filterMap);
// <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边
filterChainDefinitionMap.put("/**", "jwt");
// 未授权界面返回JSON
shiroFilterFactoryBean.setUnauthorizedUrl("/sys/common/403");
shiroFilterFactoryBean.setLoginUrl("/sys/common/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
//update-begin---author:chenrui ---date:20240126 for【QQYUN-7932】AI助手------------
@Bean
public FilterRegistrationBean shiroFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new DelegatingFilterProxy("shiroFilterFactoryBean"));
registration.setEnabled(true);
registration.addUrlPatterns("/*");
//支持异步
registration.setAsyncSupported(true);
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
return registration;
}
//update-end---author:chenrui ---date:20240126 for【QQYUN-7932】AI助手------------
@Bean("securityManager")
public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
/*
* 关闭shiro自带的session详情见文档
* http://shiro.apache.org/session-management.html#SessionManagement-
* StatelessApplications%28Sessionless%29
*/
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
securityManager.setSubjectDAO(subjectDAO);
//自定义缓存实现,使用redis
securityManager.setCacheManager(redisCacheManager());
return securityManager;
}
/**
* 下面的代码是添加注解支持
* @return
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
/**
* 解决重复代理问题 github#994
* 添加前缀判断 不匹配 任何Advisor
*/
defaultAdvisorAutoProxyCreator.setUsePrefix(true);
defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor");
return defaultAdvisorAutoProxyCreator;
}
@Bean
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
/**
* cacheManager 缓存 redis实现
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisCacheManager redisCacheManager() {
log.info("===============(1)创建缓存管理器RedisCacheManager");
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
//redis中针对不同用户缓存(此处的id需要对应user实体中的id字段,用于唯一标识)
redisCacheManager.setPrincipalIdFieldName("id");
//用户权限信息缓存时间
redisCacheManager.setExpire(200000);
return redisCacheManager;
}
/**
* RedisConfig在项目starter项目中
* jeecg-boot-starter-github\jeecg-boot-common\src\main\java\org\jeecg\common\modules\redis\config\RedisConfig.java
*
* 配置shiro redisManager
* 使用的是shiro-redis开源插件
*
* @return
*/
@Bean
public IRedisManager redisManager() {
log.info("===============(2)创建RedisManager,连接Redis..");
IRedisManager manager;
// sentinel cluster redis【issues/5569】shiro集成 redis 不支持 sentinel 方式部署的redis集群 #5569
if (Objects.nonNull(redisProperties)
&& Objects.nonNull(redisProperties.getSentinel())
&& !CollectionUtils.isEmpty(redisProperties.getSentinel().getNodes())) {
RedisSentinelManager sentinelManager = new RedisSentinelManager();
sentinelManager.setMasterName(redisProperties.getSentinel().getMaster());
sentinelManager.setHost(String.join(",", redisProperties.getSentinel().getNodes()));
sentinelManager.setPassword(redisProperties.getSentinel().getPassword());
sentinelManager.setDatabase(redisProperties.getDatabase());
return sentinelManager;
}
// redis 单机支持,在集群为空,或者集群无机器时候使用 add by jzyadmin@163.com
if (lettuceConnectionFactory.getClusterConfiguration() == null || lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().isEmpty()) {
RedisManager redisManager = new RedisManager();
redisManager.setHost(lettuceConnectionFactory.getHostName() + ":" + lettuceConnectionFactory.getPort());
//(lettuceConnectionFactory.getPort());
redisManager.setDatabase(lettuceConnectionFactory.getDatabase());
redisManager.setTimeout(0);
if (!StringUtils.isEmpty(lettuceConnectionFactory.getPassword())) {
redisManager.setPassword(lettuceConnectionFactory.getPassword());
}
manager = redisManager;
}else{
// redis集群支持优先使用集群配置
RedisClusterManager redisManager = new RedisClusterManager();
Set<HostAndPort> portSet = new HashSet<>();
lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().forEach(node -> portSet.add(new HostAndPort(node.getHost() , node.getPort())));
//update-begin--Author:scott Date:20210531 for修改集群模式下未设置redis密码的bug issues/I3QNIC
if (oConvertUtils.isNotEmpty(lettuceConnectionFactory.getPassword())) {
JedisCluster jedisCluster = new JedisCluster(portSet, 2000, 2000, 5,
lettuceConnectionFactory.getPassword(), new GenericObjectPoolConfig());
redisManager.setPassword(lettuceConnectionFactory.getPassword());
redisManager.setJedisCluster(jedisCluster);
} else {
JedisCluster jedisCluster = new JedisCluster(portSet);
redisManager.setJedisCluster(jedisCluster);
}
//update-end--Author:scott Date:20210531 for修改集群模式下未设置redis密码的bug issues/I3QNIC
manager = redisManager;
}
return manager;
}
private List<String> rebuildUrl(String[] bases, String[] uris) {
List<String> urls = new ArrayList<>();
for (String base : bases) {
for (String uri : uris) {
urls.add(prefix(base)+prefix(uri));
}
}
return urls;
}
private String prefix(String seg) {
return seg.startsWith("/") ? seg : "/"+seg;
}
}

View File

@ -1,233 +0,0 @@
package org.jeecg.config.shiro;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Set;
/**
* @Description: 用户登录鉴权和获取用户授权
* @Author: Scott
* @Date: 2019-4-23 8:13
* @Version: 1.1
*/
@Component
@Slf4j
public class ShiroRealm extends AuthorizingRealm {
@Lazy
@Resource
private CommonAPI commonApi;
@Lazy
@Resource
private RedisUtil redisUtil;
/**
* 必须重写此方法不然Shiro会报错
*/
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
/**
* 权限信息认证(包括角色以及权限)是用户访问controller的时候才进行验证(redis存储的此处权限信息)
* 触发检测用户权限时才会调用此方法例如checkRole,checkPermission
*
* @param principals 身份信息
* @return AuthorizationInfo 权限信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
log.debug("===============Shiro权限认证开始============ [ roles、permissions]==========");
String username = null;
String userId = null;
if (principals != null) {
LoginUser sysUser = (LoginUser) principals.getPrimaryPrincipal();
username = sysUser.getUsername();
userId = sysUser.getId();
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 设置用户拥有的角色集合比如“admin,test”
Set<String> roleSet = commonApi.queryUserRolesById(userId);
//System.out.println(roleSet.toString());
info.setRoles(roleSet);
// 设置用户拥有的权限集合比如“sys:role:add,sys:user:add”
Set<String> permissionSet = commonApi.queryUserAuths(userId);
info.addStringPermissions(permissionSet);
//System.out.println(permissionSet);
log.info("===============Shiro权限认证成功==============");
return info;
}
/**
* 用户信息认证是在用户进行登录的时候进行验证(不存redis)
* 也就是说验证用户输入的账号和密码是否正确,错误抛出异常
*
* @param auth 用户登录的账号密码信息
* @return 返回封装了用户信息的 AuthenticationInfo 实例
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
log.debug("===============Shiro身份认证开始============doGetAuthenticationInfo==========");
String token = (String) auth.getCredentials();
if (token == null) {
HttpServletRequest req = SpringContextUtils.getHttpServletRequest();
log.info("————————身份认证失败——————————IP地址: "+ oConvertUtils.getIpAddrByRequest(req) +"URL:"+req.getRequestURI());
throw new AuthenticationException("token为空!");
}
// 校验token有效性
LoginUser loginUser = null;
try {
loginUser = this.checkUserTokenIsEffect(token);
} catch (AuthenticationException e) {
JwtUtil.responseError(SpringContextUtils.getHttpServletResponse(),401,e.getMessage());
e.printStackTrace();
return null;
}
return new SimpleAuthenticationInfo(loginUser, token, getName());
}
/**
* 校验token的有效性
*
* @param token
*/
public LoginUser checkUserTokenIsEffect(String token) throws AuthenticationException {
// 解密获得username用于和数据库进行对比
String username = JwtUtil.getUsername(token);
if (username == null) {
throw new AuthenticationException("token非法无效!");
}
// 查询用户信息
log.debug("———校验token是否有效————checkUserTokenIsEffect——————— "+ token);
LoginUser loginUser = TokenUtils.getLoginUser(username, commonApi, redisUtil);
//LoginUser loginUser = commonApi.getUserByName(username);
if (loginUser == null) {
throw new AuthenticationException("用户不存在!");
}
// 判断用户状态
if (loginUser.getStatus() != 1) {
throw new AuthenticationException("账号已被锁定,请联系管理员!");
}
// 校验token是否超时失效 & 或者账号密码是否错误
if (!jwtTokenRefresh(token, username, loginUser.getPassword())) {
throw new AuthenticationException(CommonConstant.TOKEN_IS_INVALID_MSG);
}
//update-begin-author:taoyan date:20210609 for:校验用户的tenant_id和前端传过来的是否一致
String userTenantIds = loginUser.getRelTenantIds();
if(oConvertUtils.isNotEmpty(userTenantIds)){
String contextTenantId = TenantContext.getTenant();
log.debug("登录租户:" + contextTenantId);
log.debug("用户拥有那些租户:" + userTenantIds);
//登录用户无租户前端header中租户ID值为 0
String str ="0";
if(oConvertUtils.isNotEmpty(contextTenantId) && !str.equals(contextTenantId)){
//update-begin-author:taoyan date:20211227 for: /issues/I4O14W 用户租户信息变更判断漏洞
String[] arr = userTenantIds.split(",");
if(!oConvertUtils.isIn(contextTenantId, arr)){
boolean isAuthorization = false;
//========================================================================
// 查询用户信息(如果租户不匹配从数据库中重新查询一次用户信息)
String loginUserKey = CacheConstant.SYS_USERS_CACHE + "::" + username;
redisUtil.del(loginUserKey);
LoginUser loginUserFromDb = commonApi.getUserByName(username);
if (oConvertUtils.isNotEmpty(loginUserFromDb.getRelTenantIds())) {
String[] newArray = loginUserFromDb.getRelTenantIds().split(",");
if (oConvertUtils.isIn(contextTenantId, newArray)) {
isAuthorization = true;
}
}
//========================================================================
//*********************************************
if(!isAuthorization){
log.info("租户异常——登录租户:" + contextTenantId);
log.info("租户异常——用户拥有租户组:" + userTenantIds);
throw new AuthenticationException("登录租户授权变更,请重新登陆!");
}
//*********************************************
}
//update-end-author:taoyan date:20211227 for: /issues/I4O14W 用户租户信息变更判断漏洞
}
}
//update-end-author:taoyan date:20210609 for:校验用户的tenant_id和前端传过来的是否一致
return loginUser;
}
/**
* JWTToken刷新生命周期 (实现: 用户在线操作不掉线功能)
* 1、登录成功后将用户的JWT生成的Token作为k、v存储到cache缓存里面(这时候k、v值一样)缓存有效期设置为Jwt有效时间的2倍
* 2、当该用户再次请求时通过JWTFilter层层校验之后会进入到doGetAuthenticationInfo进行身份验证
* 3、当该用户这次请求jwt生成的token值已经超时但该token对应cache中的k还是存在则表示该用户一直在操作只是JWT的token失效了程序会给token对应的k映射的v值重新生成JWTToken并覆盖v值该缓存生命周期重新计算
* 4、当该用户这次请求jwt在生成的token值已经超时并在cache中不存在对应的k则表示该用户账户空闲超时返回用户信息已失效请重新登录。
* 注意: 前端请求Header中设置Authorization保持不变校验有效性以缓存中的token为准。
* 用户过期时间 = Jwt有效时间 * 2。
*
* @param userName
* @param passWord
* @return
*/
public boolean jwtTokenRefresh(String token, String userName, String passWord) {
String cacheToken = String.valueOf(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token));
if (oConvertUtils.isNotEmpty(cacheToken)) {
// 校验token有效性
if (!JwtUtil.verify(cacheToken, userName, passWord)) {
String newAuthorization = JwtUtil.sign(userName, passWord);
// 设置超时时间
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, newAuthorization);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME *2 / 1000);
log.debug("——————————用户在线操作更新token保证不掉线—————————jwtTokenRefresh——————— "+ token);
}
//update-begin--Author:scott Date:20191005 for解决每次请求都重写redis中 token缓存问题
// else {
// // 设置超时时间
// redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, cacheToken);
// redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
// }
//update-end--Author:scott Date:20191005 for解决每次请求都重写redis中 token缓存问题
return true;
}
//redis中不存在此TOEKN说明token非法返回false
return false;
}
/**
* 清除当前用户的权限认证缓存
*
* @param principals 权限信息
*/
@Override
public void clearCache(PrincipalCollection principals) {
super.clearCache(principals);
//update-begin---author:scott ---date::2024-06-18 for【TV360X-1320】分配权限必须退出重新登录才生效造成很多用户困扰---
super.clearCachedAuthorizationInfo(principals);
//update-end---author:scott ---date::2024-06-18 for【TV360X-1320】分配权限必须退出重新登录才生效造成很多用户困扰---
}
}

View File

@ -1,77 +0,0 @@
package org.jeecg.config.shiro.filters;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.InvalidRequestFilter;
import org.apache.shiro.web.filter.mgt.DefaultFilter;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.apache.shiro.mgt.SecurityManager;
import org.springframework.beans.factory.BeanInitializationException;
import jakarta.servlet.Filter;
import java.util.Map;
/**
* 自定义ShiroFilterFactoryBean解决资源中文路径问题
* @author: jeecg-boot
*/
@Slf4j
public class CustomShiroFilterFactoryBean extends ShiroFilterFactoryBean {
@Override
public Class getObjectType() {
return MySpringShiroFilter.class;
}
@Override
protected AbstractShiroFilter createInstance() throws Exception {
SecurityManager securityManager = getSecurityManager();
if (securityManager == null) {
String msg = "SecurityManager property must be set.";
throw new BeanInitializationException(msg);
}
if (!(securityManager instanceof WebSecurityManager)) {
String msg = "The security manager does not implement the WebSecurityManager interface.";
throw new BeanInitializationException(msg);
}
FilterChainManager manager = createFilterChainManager();
//Expose the constructed FilterChainManager by first wrapping it in a
// FilterChainResolver implementation. The AbstractShiroFilter implementations
// do not know about FilterChainManagers - only resolvers:
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
chainResolver.setFilterChainManager(manager);
Map<String, Filter> filterMap = manager.getFilters();
Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name());
if (invalidRequestFilter instanceof InvalidRequestFilter) {
//此处是关键,设置false跳过URL携带中文400servletPath中文校验bug
((InvalidRequestFilter) invalidRequestFilter).setBlockNonAscii(false);
}
//Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built
//FilterChainResolver. It doesn't matter that the instance is an anonymous inner class
//here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts
//injection of the SecurityManager and FilterChainResolver:
return new MySpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
}
private static final class MySpringShiroFilter extends AbstractShiroFilter {
protected MySpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
if (webSecurityManager == null) {
throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
} else {
this.setSecurityManager(webSecurityManager);
if (resolver != null) {
this.setFilterChainResolver(resolver);
}
}
}
}
}

View File

@ -1,130 +0,0 @@
package org.jeecg.config.shiro.filters;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.shiro.JwtToken;
import org.jeecg.config.shiro.ignore.InMemoryIgnoreAuth;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/**
* @Description: 鉴权登录拦截器
* @Author: Scott
* @Date: 2018/10/7
**/
@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter {
/**
* 默认开启跨域设置(使用单体)
* 微服务情况下此属性设置为false
*/
private boolean allowOrigin = true;
public JwtFilter(){}
public JwtFilter(boolean allowOrigin){
this.allowOrigin = allowOrigin;
}
/**
* 执行登录认证
*
* @param request
* @param response
* @param mappedValue
* @return
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
try {
// 判断当前路径是不是注解了@IngoreAuth路径如果是则放开验证
if (InMemoryIgnoreAuth.contains(((HttpServletRequest) request).getServletPath())) {
return true;
}
executeLogin(request, response);
return true;
} catch (Exception e) {
JwtUtil.responseError(response,401,CommonConstant.TOKEN_IS_INVALID_MSG);
return false;
//throw new AuthenticationException("Token失效请重新登录", e);
}
}
/**
*
*/
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String token = httpServletRequest.getHeader(CommonConstant.X_ACCESS_TOKEN);
// update-begin--Author:lvdandan Date:20210105 forJT-355 OA聊天添加token验证获取token参数
if (oConvertUtils.isEmpty(token)) {
token = httpServletRequest.getParameter("token");
}
// update-end--Author:lvdandan Date:20210105 forJT-355 OA聊天添加token验证获取token参数
JwtToken jwtToken = new JwtToken(token);
// 提交给realm进行登入如果错误他会抛出异常并被捕获
getSubject(request, response).login(jwtToken);
// 如果没有抛出异常则代表登入成功返回true
return true;
}
/**
* 对跨域提供支持
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
if(allowOrigin){
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, httpServletRequest.getHeader(HttpHeaders.ORIGIN));
// 允许客户端请求方法
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,POST,OPTIONS,PUT,DELETE");
// 允许客户端提交的Header
String requestHeaders = httpServletRequest.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS);
if (StringUtils.isNotEmpty(requestHeaders)) {
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders);
}
// 允许客户端携带凭证信息(是否允许发送Cookie)
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
}
// 跨域时会首先发送一个option请求这里我们给option请求直接返回正常状态
if (RequestMethod.OPTIONS.name().equalsIgnoreCase(httpServletRequest.getMethod())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
//update-begin-author:taoyan date:20200708 for:多租户用到
String tenantId = httpServletRequest.getHeader(CommonConstant.TENANT_ID);
TenantContext.setTenant(tenantId);
//update-end-author:taoyan date:20200708 for:多租户用到
return super.preHandle(request, response);
}
/**
* JwtFilter中ThreadLocal需要及时清除 #3634
*
* @param request
* @param response
* @param exception
* @throws Exception
*/
@Override
public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception {
//log.info("------清空线程中多租户的ID={}------",TenantContext.getTenant());
TenantContext.clear();
}
}

View File

@ -1,67 +0,0 @@
package org.jeecg.config.shiro.filters;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import lombok.extern.slf4j.Slf4j;
/**
* @Author Scott
* @create 2019-02-01 15:56
* @desc 鉴权请求URL访问权限拦截器
*/
@Slf4j
public class ResourceCheckFilter extends AccessControlFilter {
private String errorUrl;
public String getErrorUrl() {
return errorUrl;
}
public void setErrorUrl(String errorUrl) {
this.errorUrl = errorUrl;
}
/**
* 表示是否允许访问 如果允许访问返回true否则false
*
* @param servletRequest
* @param servletResponse
* @param o 表示写在拦截器中括号里面的字符串 mappedValue 就是 [urls] 配置中拦截器参数部分
* @return
* @throws Exception
*/
@Override
protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
Subject subject = getSubject(servletRequest, servletResponse);
String url = getPathWithinApplication(servletRequest);
log.info("当前用户正在访问的 url => " + url);
return subject.isPermitted(url);
}
/**
* onAccessDenied表示当访问拒绝时是否已经处理了 如果返回 true 表示需要继续处理; 如果返回 false
* 表示该拦截器实例已经处理了,将直接返回即可。
*
* @param servletRequest
* @param servletResponse
* @return
* @throws Exception
*/
@Override
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
log.info("当 isAccessAllowed 返回 false 的时候,才会执行 method onAccessDenied ");
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.sendRedirect(request.getContextPath() + this.errorUrl);
// 返回 false 表示已经处理,例如页面跳转啥的,表示不在走以下的拦截器了(如果还有配置的话)
return false;
}
}

View File

@ -7,10 +7,15 @@ import org.springframework.aop.framework.Advised;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
@ -45,6 +50,9 @@ public class IgnoreAuthPostProcessor implements ApplicationListener<ContextRefre
log.info("Init Token ignoreAuthUrls Config [ 集合 ] {}", ignoreAuthUrls);
if (!CollectionUtils.isEmpty(ignoreAuthUrls)) {
InMemoryIgnoreAuth.set(ignoreAuthUrls);
// 添加免登录url
addIgnoreUrl(ignoreAuthUrls);
}
// 计算方法的耗时
@ -110,4 +118,28 @@ public class IgnoreAuthPostProcessor implements ApplicationListener<ContextRefre
private String prefix(String seg) {
return seg.startsWith("/") ? seg : "/"+seg;
}
private void addIgnoreUrl(List<String> urls){
FilterChainProxy obj = applicationContext.getBean(FilterChainProxy.class);
if (Objects.isNull(obj)) {
return;
}
List<SecurityFilterChain> filterChains = (List<SecurityFilterChain>) getProperty(obj,"filterChains");
if (!CollectionUtils.isEmpty(filterChains)) {
for (String url : urls) {
filterChains.add(0, new DefaultSecurityFilterChain(new AntPathRequestMatcher(url, null)));
}
}
}
private Object getProperty(Object obj, String fieldName) {
try {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
return null;
}
}
}

View File

@ -1,18 +0,0 @@
package org.jeecg.config.vo;
/**
* @Description: TODO
* @author: scott
* @date: 2022年01月21日 14:23
*/
public class Shiro {
private String excludeUrls = "";
public String getExcludeUrls() {
return excludeUrls;
}
public void setExcludeUrls(String excludeUrls) {
this.excludeUrls = excludeUrls;
}
}

View File

@ -2,10 +2,10 @@ package org.jeecg.modules.base.service.impl;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.dto.LogDTO;
import org.jeecg.common.constant.enums.ClientTerminalTypeEnum;
import org.jeecg.common.util.BrowserUtils;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.base.mapper.BaseCommonMapper;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.common.system.vo.LoginUser;
@ -35,7 +35,7 @@ public class BaseCommonServiceImpl implements BaseCommonService {
logDTO.setId(String.valueOf(IdWorker.getId()));
}
//保存日志异常捕获处理防止数据太大存储失败导致业务失败JT-238
try {
try {
logDTO.setCreateTime(new Date());
baseCommonMapper.saveLog(logDTO);
} catch (Exception e) {
@ -74,7 +74,7 @@ public class BaseCommonServiceImpl implements BaseCommonService {
//获取登录用户信息
if(user==null){
try {
user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
user = SecureUtil.currentUser();
} catch (Exception e) {
//e.printStackTrace();
}

View File

@ -11,8 +11,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.aspect.annotation.PermissionData;
@ -479,8 +477,8 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
public Mono<String> test() {
//解决shiro报错No SecurityManager accessible to the calling code, either bound to the org.apache.shiro
// https://blog.csdn.net/Japhet_jiu/article/details/131177210
DefaultSecurityManager securityManager = new DefaultSecurityManager();
SecurityUtils.setSecurityManager(securityManager);
// DefaultSecurityManager securityManager = new DefaultSecurityManager();
// SecurityUtils.setSecurityManager(securityManager);
return Mono.just("测试");
}

View File

@ -5,15 +5,16 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.demo.test.entity.JeecgDemo;
import org.jeecg.modules.demo.test.entity.JeecgOrderCustomer;
import org.jeecg.modules.demo.test.entity.JeecgOrderMain;
@ -30,6 +31,7 @@ import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@ -184,7 +186,7 @@ public class JeecgOrderMainController extends JeecgController<JeecgOrderMain, IJ
//Step.2 AutoPoi 导出Excel
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
//获取当前用户
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
List<JeecgOrderMainPage> pageList = new ArrayList<JeecgOrderMainPage>();

View File

@ -1,17 +1,19 @@
package org.jeecg.modules.demo.test.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.demo.test.entity.JeecgDemo;
import org.jeecg.modules.demo.test.mapper.JeecgDemoMapper;
import org.jeecg.modules.demo.test.service.IJeecgDemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -81,7 +83,7 @@ public class JeecgDemoServiceImpl extends ServiceImpl<JeecgDemoMapper, JeecgDemo
@Override
public String getExportFields() {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
//权限配置列导出示例
//1.配置前缀与菜单中配置的列前缀一致
List<String> noAuthList = new ArrayList<>();

View File

@ -792,4 +792,18 @@ public interface ISysBaseAPI extends CommonAPI {
@RequestParam(value = "fields", required = false) String... fields
);
@GetMapping("/sys/api/getUserByPhone")
public LoginUser getUserByPhone(@RequestParam("phone") String phone);
@GetMapping("/sys/api/queryAllDictItems")
Map<String,List<DictModel>> queryAllDictItems();
@GetMapping("/sys/api/queryUserDeparts")
List<SysDepartModel> queryUserDeparts(@RequestParam("userId") String userId);
@PostMapping("/sys/api/updateUserDepart")
void updateUserDepart(@RequestParam("username") String username,@RequestParam("orgCode") String orgCode,@RequestParam("loginTenantId") Integer loginTenantId);
@GetMapping("/sys/api/setLoginTenant")
JSONObject setLoginTenant(@RequestParam("username") String username);
}

View File

@ -464,4 +464,28 @@ public class SysBaseAPIFallback implements ISysBaseAPI {
return false;
}
@Override
public Map<String, List<DictModel>> queryAllDictItems() {
return null;
}
@Override
public List<SysDepartModel> queryUserDeparts(String userId) {
return null;
}
@Override
public void updateUserDepart(String username, String orgCode, Integer loginTenantId) {
}
@Override
public LoginUser getUserByPhone(String phone) {
return null;
}
@Override
public JSONObject setLoginTenant(String username) {
return null;
}
}

View File

@ -1,6 +1,6 @@
package org.jeecg.modules.aop;
import org.apache.shiro.SecurityUtils;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
@ -10,9 +10,11 @@ import org.aspectj.lang.reflect.MethodSignature;
import org.jeecg.common.api.dto.LogDTO;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.SysTenantPack;
import org.jeecg.modules.system.entity.SysTenantPackUser;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
@ -79,7 +81,7 @@ public class TenantPackUserLogAspect {
dto.setOperateType(opType);
dto.setTenantId(tenantId);
//获取登录用户信息
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
if(sysUser!=null){
dto.setUserid(sysUser.getUsername());
dto.setUsername(sysUser.getRealname());

View File

@ -974,4 +974,29 @@ public class SystemApiController {
return sysBaseApi.dictTableWhiteListCheckByDict(tableOrDictCode, fields);
}
@GetMapping("/sys/api/getUserByPhone")
public LoginUser getUserByPhone(String phone) {
return sysBaseApi.getUserByPhone(phone);
}
@GetMapping("/sys/api/queryAllDictItems")
public Map<String,List<DictModel>> queryAllDictItems() {
return sysBaseApi.queryAllDictItems();
}
@GetMapping("/sys/api/queryUserDeparts")
public List<SysDepartModel> queryUserDeparts(@RequestParam("userId") String userId) {
return sysBaseApi.queryUserDeparts(userId);
}
@PostMapping("/sys/api/updateUserDepart")
public void updateUserDepart(@RequestParam("username") String username,@RequestParam("orgCode") String orgCode,@RequestParam("loginTenantId") Integer loginTenantId) {
sysBaseApi.updateUserDepart(username, orgCode, loginTenantId);
}
@GetMapping("/sys/api/setLoginTenant")
public JSONObject setLoginTenant(@RequestParam("username") String username) {
return sysBaseApi.setLoginTenant(username);
}
}

View File

@ -2,13 +2,12 @@ package org.jeecg.modules.oss.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.modules.oss.entity.OssFile;
import org.jeecg.modules.oss.service.IOssFileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -48,7 +47,7 @@ public class OssFileController {
@ResponseBody
@PostMapping("/upload")
//@RequiresRoles("admin")
@RequiresPermissions("system:ossFile:upload")
@PreAuthorize("@jps.requiresPermissions('system:ossFile:upload')")
public Result upload(@RequestParam("file") MultipartFile multipartFile) {
Result result = new Result();
try {

View File

@ -1,20 +1,19 @@
package org.jeecg.modules.quartz.controller;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.ImportExcelUtil;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.quartz.entity.QuartzJob;
import org.jeecg.modules.quartz.service.IQuartzJobService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
@ -25,6 +24,8 @@ import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@ -80,7 +81,7 @@ public class QuartzJobController {
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:add")
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:add')")
@RequestMapping(value = "/add", method = RequestMethod.POST)
public Result<?> add(@RequestBody QuartzJob quartzJob) {
quartzJobService.saveAndScheduleJob(quartzJob);
@ -94,7 +95,7 @@ public class QuartzJobController {
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:edit")
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:edit')")
@RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
public Result<?> eidt(@RequestBody QuartzJob quartzJob) {
try {
@ -113,7 +114,7 @@ public class QuartzJobController {
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:delete")
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:delete')")
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
QuartzJob quartzJob = quartzJobService.getById(id);
@ -132,7 +133,7 @@ public class QuartzJobController {
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:deleteBatch')")
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
if (ids == null || "".equals(ids.trim())) {
@ -152,7 +153,7 @@ public class QuartzJobController {
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:pause")
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:pause')")
@GetMapping(value = "/pause")
@Operation(summary = "停止定时任务")
public Result<Object> pauseJob(@RequestParam(name = "id") String id) {
@ -171,7 +172,7 @@ public class QuartzJobController {
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:resume")
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:resume')")
@GetMapping(value = "/resume")
@Operation(summary = "启动定时任务")
public Result<Object> resumeJob(@RequestParam(name = "id") String id) {
@ -214,7 +215,7 @@ public class QuartzJobController {
mv.addObject(NormalExcelConstants.CLASS, QuartzJob.class);
//获取当前登录用户
//update-begin---author:wangshuai ---date:20211227 for[JTC-116]导出人写死了------------
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("定时任务列表数据", "导出人:"+user.getRealname(), "导出信息"));
//update-end---author:wangshuai ---date:20211227 for[JTC-116]导出人写死了------------
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
@ -272,7 +273,7 @@ public class QuartzJobController {
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:execute")
@PreAuthorize("@jps.requiresPermissions('system:quartzJob:execute')")
@GetMapping("/execute")
public Result<?> execute(@RequestParam(name = "id", required = true) String id) {
QuartzJob quartzJob = quartzJobService.getById(id);

View File

@ -1,6 +1,8 @@
package org.jeecg.modules.system.controller;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -9,7 +11,6 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
@ -20,10 +21,10 @@ import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*;
import org.jeecg.common.util.encryption.EncryptedString;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysRoleIndex;
import org.jeecg.modules.system.entity.SysTenant;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.SysLoginModel;
import org.jeecg.modules.system.service.*;
@ -31,14 +32,23 @@ import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
import org.jeecg.modules.system.util.RandImageUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.event.LogoutSuccessEvent;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Author scott
@ -67,9 +77,18 @@ public class LoginController {
private BaseCommonService baseCommonService;
@Autowired
private JeecgBaseConfig jeecgBaseConfig;
@Autowired
private OAuth2AuthorizationService authorizationService;
@Autowired
private CacheManager cacheManager;
private final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
/**
* 使用spring authorization server提供的各类登录接口
* @param sysLoginModel
* @return
*/
@Operation(summary = "登录接口")
@RequestMapping(value = "/login", method = RequestMethod.POST)
public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request){
@ -164,8 +183,6 @@ public class LoginController {
obj.put("userInfo",sysUser);
obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
log.info("3 获取用户信息耗时 (字典数据)" + (System.currentTimeMillis() - start) + "毫秒");
result.setResult(obj);
result.success("");
}
@ -201,7 +218,15 @@ public class LoginController {
//清空用户的缓存信息包括部门信息例如sys:cache:user::<username>
redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
//调用shiro的logout
SecurityUtils.getSubject().logout();
// SecurityUtils.getSubject().logout();
OAuth2Authorization authorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
// 清空用户信息
cacheManager.getCache("user_details").evict(authorization.getPrincipalName());
// 清空access token
authorizationService.remove(authorization);
return Result.ok("退出登录成功!");
}else {
return Result.error("Token无效!");
@ -271,7 +296,7 @@ public class LoginController {
Result<JSONObject> result = new Result<JSONObject>();
String username = user.getUsername();
if(oConvertUtils.isEmpty(username)) {
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
username = sysUser.getUsername();
}
@ -554,7 +579,7 @@ public class LoginController {
/**
* 切换菜单表为vue3的表
*/
@RequiresRoles({"admin"})
@PreAuthorize("@jps.requiresRoles('admin')")
@GetMapping(value = "/switchVue3Menu")
public Result<String> switchVue3Menu(HttpServletResponse response) {
Result<String> res = new Result<String>();

View File

@ -1,5 +1,7 @@
package org.jeecg.modules.system.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -19,6 +21,7 @@ import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.message.enums.RangeDateEnum;
import org.jeecg.modules.message.websocket.WebSocket;
import org.jeecg.modules.system.entity.SysAnnouncement;
@ -38,6 +41,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -48,10 +52,7 @@ import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
@ -338,7 +339,7 @@ public class SysAnnouncementController {
long start = System.currentTimeMillis();
Result<Map<String,Object>> result = new Result<Map<String,Object>>();
Map<String,Object> sysMsgMap = new HashMap(5);
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
String userId = sysUser.getId();
@ -410,7 +411,7 @@ public class SysAnnouncementController {
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "系统通告列表");
mv.addObject(NormalExcelConstants.CLASS, SysAnnouncement.class);
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("系统通告列表数据", "导出人:"+user.getRealname(), "导出信息"));
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
return mv;
@ -578,7 +579,7 @@ public class SysAnnouncementController {
JSONObject obj = new JSONObject();
obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_USER);
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
webSocket.sendMessage(sysUser.getId(), obj.toJSONString());
// 4、性能统计耗时

View File

@ -3,9 +3,9 @@ package org.jeecg.modules.system.controller;
import java.util.Arrays;
import java.util.Date;
import com.alibaba.fastjson.JSON;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.DataBaseConstant;
@ -13,11 +13,13 @@ import org.jeecg.common.constant.WebsocketConst;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.SqlInjectionUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.message.websocket.WebSocket;
import org.jeecg.modules.system.entity.SysAnnouncementSend;
import org.jeecg.modules.system.model.AnnouncementSendModel;
import org.jeecg.modules.system.service.ISysAnnouncementSendService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@ -194,7 +196,7 @@ public class SysAnnouncementSendController {
public Result<SysAnnouncementSend> editById(@RequestBody JSONObject json) {
Result<SysAnnouncementSend> result = new Result<SysAnnouncementSend>();
String anntId = json.getString("anntId");
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
String userId = sysUser.getId();
LambdaUpdateWrapper<SysAnnouncementSend> updateWrapper = new UpdateWrapper().lambda();
updateWrapper.set(SysAnnouncementSend::getReadFlag, CommonConstant.HAS_READ_FLAG);
@ -219,7 +221,7 @@ public class SysAnnouncementSendController {
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
Result<IPage<AnnouncementSendModel>> result = new Result<IPage<AnnouncementSendModel>>();
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
String userId = sysUser.getId();
announcementSendModel.setUserId(userId);
announcementSendModel.setPageNo((pageNo-1)*pageSize);
@ -238,7 +240,7 @@ public class SysAnnouncementSendController {
@PutMapping(value = "/readAll")
public Result<SysAnnouncementSend> readAll() {
Result<SysAnnouncementSend> result = new Result<SysAnnouncementSend>();
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
String userId = sysUser.getId();
LambdaUpdateWrapper<SysAnnouncementSend> updateWrapper = new UpdateWrapper().lambda();
updateWrapper.set(SysAnnouncementSend::getReadFlag, CommonConstant.HAS_READ_FLAG);

View File

@ -7,7 +7,6 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CommonConstant;
@ -18,6 +17,7 @@ import org.jeecg.common.util.ImportExcelUtil;
import org.jeecg.common.util.ReflectHelper;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.system.entity.SysCategory;
import org.jeecg.modules.system.model.TreeSelectModel;
import org.jeecg.modules.system.service.ISysCategoryService;
@ -27,6 +27,7 @@ import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@ -237,7 +238,7 @@ public class SysCategoryController {
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "分类字典列表");
mv.addObject(NormalExcelConstants.CLASS, SysCategory.class);
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("分类字典列表数据", "导出人:"+user.getRealname(), "导出信息"));
return mv;
}

View File

@ -1,12 +1,12 @@
package org.jeecg.modules.system.controller;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.dto.DataLogDTO;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
@ -14,12 +14,14 @@ import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.system.entity.SysComment;
import org.jeecg.modules.system.service.ISysCommentService;
import org.jeecg.modules.system.vo.SysCommentFileVo;
import org.jeecg.modules.system.vo.SysCommentVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
@ -126,7 +128,7 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
if(comment==null){
return Result.error("该评论已被删除!");
}
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
String username = sysUser.getUsername();
String admin = "admin";
//除了admin外 其他人只能删除自己的评论

View File

@ -12,7 +12,6 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.config.TenantContext;
@ -27,6 +26,7 @@ import org.jeecg.modules.system.entity.SysDataSource;
import org.jeecg.modules.system.service.ISysDataSourceService;
import org.jeecg.modules.system.util.SecurityUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
@ -60,7 +60,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
*/
@AutoLog(value = "多数据源管理-分页列表查询")
@Operation(summary = "多数据源管理-分页列表查询")
@RequiresPermissions("system:datasource:list")
@PreAuthorize("@jps.requiresPermissions('system:datasource:list')")
@GetMapping(value = "/list")
public Result<?> queryPageList(
SysDataSource sysDataSource,

View File

@ -1,12 +1,11 @@
package org.jeecg.modules.system.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CacheConstant;
@ -18,6 +17,7 @@ import org.jeecg.common.util.ImportExcelUtil;
import org.jeecg.common.util.YouBianCodeUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.DepartIdModel;
@ -35,6 +35,8 @@ import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@ -73,7 +75,7 @@ public class SysDepartController {
@RequestMapping(value = "/queryMyDeptTreeList", method = RequestMethod.GET)
public Result<List<SysDepartTreeModel>> queryMyDeptTreeList() {
Result<List<SysDepartTreeModel>> result = new Result<>();
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
try {
if(oConvertUtils.isNotEmpty(user.getUserIdentity()) && user.getUserIdentity().equals( CommonConstant.USER_IDENTITY_2 )){
//update-begin--Author:liusq Date:20210624 for:部门查询ids为空后的前端显示问题 issues/I3UD06
@ -177,7 +179,7 @@ public class SysDepartController {
* @param sysDepart
* @return
*/
@RequiresPermissions("system:depart:add")
@PreAuthorize("@jps.requiresPermissions('system:depart:add')")
@RequestMapping(value = "/add", method = RequestMethod.POST)
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
public Result<SysDepart> add(@RequestBody SysDepart sysDepart, HttpServletRequest request) {
@ -203,7 +205,7 @@ public class SysDepartController {
* @param sysDepart
* @return
*/
@RequiresPermissions("system:depart:edit")
@PreAuthorize("@jps.requiresPermissions('system:depart:edit')")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
public Result<SysDepart> edit(@RequestBody SysDepart sysDepart, HttpServletRequest request) {
@ -231,7 +233,7 @@ public class SysDepartController {
* @param id
* @return
*/
@RequiresPermissions("system:depart:delete")
@PreAuthorize("@jps.requiresPermissions('system:depart:delete')")
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
public Result<SysDepart> delete(@RequestParam(name="id",required=true) String id) {
@ -257,7 +259,7 @@ public class SysDepartController {
* @param ids
* @return
*/
@RequiresPermissions("system:depart:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('system:depart:deleteBatch')")
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
public Result<SysDepart> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
@ -321,7 +323,7 @@ public class SysDepartController {
public Result<List<SysDepartTreeModel>> searchBy(@RequestParam(name = "keyWord", required = true) String keyWord,@RequestParam(name = "myDeptSearch", required = false) String myDeptSearch) {
Result<List<SysDepartTreeModel>> result = new Result<List<SysDepartTreeModel>>();
//部门查询myDeptSearch为1时为我的部门查询登录用户为上级时查只查负责部门下数据
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
String departIds = null;
if(oConvertUtils.isNotEmpty(user.getUserIdentity()) && user.getUserIdentity().equals( CommonConstant.USER_IDENTITY_2 )){
departIds = user.getDepartIds();
@ -370,7 +372,7 @@ public class SysDepartController {
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "部门列表");
mv.addObject(NormalExcelConstants.CLASS, SysDepartExportVo.class);
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("导入规则:\n" +
"1、标题为第三行部门路径和部门名称的标题不允许修改否则会匹配失败第四行为数据填写范围;\n" +
"2、部门路径用英文字符/分割,部门名称为部门路径的最后一位;\n" +
@ -391,7 +393,7 @@ public class SysDepartController {
* @param response
* @return
*/
@RequiresPermissions("system:depart:importExcel")
@PreAuthorize("@jps.requiresPermissions('system:depart:importExcel')")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
@ -627,7 +629,7 @@ public class SysDepartController {
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "部门列表");
mv.addObject(NormalExcelConstants.CLASS, ExportDepartVo.class);
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("部门列表数据", "导出人:"+user.getRealname(), "导出信息"));
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
return mv;

View File

@ -1,5 +1,6 @@
package org.jeecg.modules.system.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -10,13 +11,13 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.SysDepartPermission;
import org.jeecg.modules.system.entity.SysDepartRolePermission;
@ -28,6 +29,7 @@ import org.jeecg.modules.system.service.ISysDepartRolePermissionService;
import org.jeecg.modules.system.service.ISysPermissionDataRuleService;
import org.jeecg.modules.system.service.ISysPermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
@ -258,7 +260,7 @@ public class SysDepartPermissionController extends JeecgController<SysDepartPerm
this.sysDepartRolePermissionService.saveDeptRolePermission(roleId, permissionIds, lastPermissionIds);
result.success("保存成功!");
//update-begin---author:wangshuai ---date:20220316 for[VUEN-234]部门角色授权添加敏感日志------------
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser loginUser = SecureUtil.currentUser();
baseCommonService.addLog("修改部门角色ID:"+roleId+"的权限配置,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
//update-end---author:wangshuai ---date:20220316 for[VUEN-234]部门角色授权添加敏感日志------------
log.info("======部门角色授权成功=====耗时:" + (System.currentTimeMillis() - start) + "毫秒");

View File

@ -3,23 +3,21 @@ package org.jeecg.modules.system.controller;
import java.util.*;
import java.util.stream.Collectors;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.*;
import org.jeecg.modules.system.service.*;
@ -30,6 +28,8 @@ import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
@ -80,8 +80,8 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
HttpServletRequest req) {
QueryWrapper<SysDepartRole> queryWrapper = QueryGenerator.initQueryWrapper(sysDepartRole, req.getParameterMap());
Page<SysDepartRole> page = new Page<SysDepartRole>(pageNo, pageSize);
// LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
// List<String> deptIds = null;
LoginUser user = SecureUtil.currentUser();
List<String> deptIds = null;
// if(oConvertUtils.isEmpty(deptId)){
// if(oConvertUtils.isNotEmpty(user.getUserIdentity()) && user.getUserIdentity().equals(CommonConstant.USER_IDENTITY_2) ){
// deptIds = sysDepartService.getMySubDepIdsByDepId(user.getDepartIds());
@ -108,7 +108,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
* @param sysDepartRole
* @return
*/
@RequiresPermissions("system:depart:role:add")
@PreAuthorize("@jps.requiresPermissions('system:depart:role:add')")
@Operation(summary="部门角色-添加")
@PostMapping(value = "/add")
public Result<?> add(@RequestBody SysDepartRole sysDepartRole) {
@ -123,7 +123,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
* @return
*/
@Operation(summary="部门角色-编辑")
@RequiresPermissions("system:depart:role:edit")
@PreAuthorize("@jps.requiresPermissions('system:depart:role:edit')")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<?> edit(@RequestBody SysDepartRole sysDepartRole) {
sysDepartRoleService.updateById(sysDepartRole);
@ -138,7 +138,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
*/
@AutoLog(value = "部门角色-通过id删除")
@Operation(summary="部门角色-通过id删除")
@RequiresPermissions("system:depart:role:delete")
@PreAuthorize("@jps.requiresPermissions('system:depart:role:delete')")
@DeleteMapping(value = "/delete")
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
sysDepartRoleService.removeById(id);
@ -153,7 +153,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
*/
@AutoLog(value = "部门角色-批量删除")
@Operation(summary="部门角色-批量删除")
@RequiresPermissions("system:depart:role:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('system:depart:role:deleteBatch')")
@DeleteMapping(value = "/deleteBatch")
public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.sysDepartRoleService.removeByIds(Arrays.asList(ids.split(",")));
@ -193,7 +193,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
* @param json
* @return
*/
@RequiresPermissions("system:depart:role:userAdd")
@PreAuthorize("@jps.requiresPermissions('system:depart:role:userAdd')")
@RequestMapping(value = "/deptRoleUserAdd", method = RequestMethod.POST)
public Result<?> deptRoleAdd(@RequestBody JSONObject json) {
String newRoleId = json.getString("newRoleId");
@ -201,7 +201,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
String userId = json.getString("userId");
departRoleUserService.deptRoleUserAdd(userId,newRoleId,oldRoleId);
//update-begin---author:wangshuai ---date:20220316 for[VUEN-234]部门角色分配添加敏感日志------------
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser loginUser = SecureUtil.currentUser();
baseCommonService.addLog("给部门用户ID"+userId+"分配角色,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
//update-end---author:wangshuai ---date:20220316 for[VUEN-234]部门角色分配添加敏感日志------------
return Result.ok("添加成功!");

View File

@ -7,9 +7,6 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CacheConstant;
@ -19,12 +16,10 @@ import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.DictModel;
import org.jeecg.common.system.vo.DictQuery;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.ImportExcelUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.common.util.*;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.shiro.ShiroRealm;
import org.jeecg.config.security.JeecgPermissionService;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.system.entity.SysDict;
import org.jeecg.modules.system.entity.SysDictItem;
import org.jeecg.modules.system.model.SysDictTree;
@ -43,6 +38,8 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@ -75,8 +72,8 @@ public class SysDictController {
@Autowired
private RedisUtil redisUtil;
@Autowired
private ShiroRealm shiroRealm;
private JeecgPermissionService jeecgPermissionService;
@RequestMapping(value = "/list", method = RequestMethod.GET)
public Result<IPage<SysDict>> queryPageList(SysDict sysDict,@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,HttpServletRequest req) {
@ -378,7 +375,7 @@ public class SysDictController {
* @param sysDict
* @return
*/
@RequiresPermissions("system:dict:add")
@PreAuthorize("@jps.requiresPermissions('system:dict:add')")
@RequestMapping(value = "/add", method = RequestMethod.POST)
public Result<SysDict> add(@RequestBody SysDict sysDict) {
Result<SysDict> result = new Result<SysDict>();
@ -399,7 +396,7 @@ public class SysDictController {
* @param sysDict
* @return
*/
@RequiresPermissions("system:dict:edit")
@PreAuthorize("@jps.requiresPermissions('system:dict:edit')")
@RequestMapping(value = "/edit", method = { RequestMethod.PUT,RequestMethod.POST })
public Result<SysDict> edit(@RequestBody SysDict sysDict) {
Result<SysDict> result = new Result<SysDict>();
@ -421,7 +418,7 @@ public class SysDictController {
* @param id
* @return
*/
@RequiresPermissions("system:dict:delete")
@PreAuthorize("@jps.requiresPermissions('system:dict:delete')")
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
public Result<SysDict> delete(@RequestParam(name="id",required=true) String id) {
@ -440,7 +437,7 @@ public class SysDictController {
* @param ids
* @return
*/
@RequiresPermissions("system:dict:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('system:dict:deleteBatch')")
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
@CacheEvict(value= {CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
public Result<SysDict> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
@ -491,11 +488,8 @@ public class SysDictController {
//update-end-author:liusq date:20230404 for: [issue/4358]springCache中的清除缓存的操作使用了“keys”
//update-begin---author:scott ---date:2024-06-18 for【TV360X-1320】分配权限必须退出重新登录才生效造成很多用户困扰---
// 清除当前用户的授权缓存信息
Subject currentUser = SecurityUtils.getSubject();
if (currentUser.isAuthenticated()) {
shiroRealm.clearCache(currentUser.getPrincipals());
}
// 清除权限缓存
jeecgPermissionService.clearCache();
//update-end---author:scott ---date::2024-06-18 for【TV360X-1320】分配权限必须退出重新登录才生效造成很多用户困扰---
return result;
}
@ -539,7 +533,7 @@ public class SysDictController {
// 注解对象Class
mv.addObject(NormalExcelConstants.CLASS, SysDictPage.class);
// 自定义表格参数
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("数据字典列表", "导出人:"+user.getRealname(), "数据字典"));
// 导出数据列表
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
@ -553,7 +547,7 @@ public class SysDictController {
* @param
* @return
*/
@RequiresPermissions("system:dict:importExcel")
@PreAuthorize("@jps.requiresPermissions('system:dict:importExcel')")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;

View File

@ -10,8 +10,6 @@ import jakarta.servlet.http.HttpServletRequest;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.system.query.QueryGenerator;
@ -20,6 +18,7 @@ import org.jeecg.modules.system.entity.SysDictItem;
import org.jeecg.modules.system.service.ISysDictItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@ -74,7 +73,7 @@ public class SysDictItemController {
* @功能:新增
* @return
*/
@RequiresPermissions("system:dict:item:add")
@PreAuthorize("@jps.requiresPermissions('system:dict:item:add')")
@RequestMapping(value = "/add", method = RequestMethod.POST)
@CacheEvict(value= {CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
public Result<SysDictItem> add(@RequestBody SysDictItem sysDictItem) {
@ -95,7 +94,7 @@ public class SysDictItemController {
* @param sysDictItem
* @return
*/
@RequiresPermissions("system:dict:item:edit")
@PreAuthorize("@jps.requiresPermissions('system:dict:item:edit')")
@RequestMapping(value = "/edit", method = { RequestMethod.PUT,RequestMethod.POST })
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
public Result<SysDictItem> edit(@RequestBody SysDictItem sysDictItem) {
@ -119,7 +118,7 @@ public class SysDictItemController {
* @param id
* @return
*/
@RequiresPermissions("system:dict:item:delete")
@PreAuthorize("@jps.requiresPermissions('system:dict:item:delete')")
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
public Result<SysDictItem> delete(@RequestParam(name="id",required=true) String id) {
@ -141,7 +140,7 @@ public class SysDictItemController {
* @param ids
* @return
*/
@RequiresPermissions("system:dict:item:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('system:dict:item:deleteBatch')")
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
public Result<SysDictItem> deleteBatch(@RequestParam(name="ids",required=true) String ids) {

View File

@ -5,13 +5,13 @@ import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.entity.SysGatewayRoute;
import org.jeecg.modules.system.service.ISysGatewayRouteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@ -67,7 +67,7 @@ public class SysGatewayRouteController extends JeecgController<SysGatewayRoute,
* @param id
* @return
*/
@RequiresPermissions("system:getway:delete")
@PreAuthorize("@jps.requiresPermissions('system:getway:delete')")
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
sysGatewayRouteService.deleteById(id);

View File

@ -5,9 +5,7 @@ import java.util.Arrays;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.entity.SysLog;

View File

@ -1,13 +1,12 @@
package org.jeecg.modules.system.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
@ -16,7 +15,8 @@ import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.Md5Util;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.shiro.ShiroRealm;
import org.jeecg.config.security.JeecgPermissionService;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.constant.DefIndexConst;
import org.jeecg.modules.system.entity.*;
@ -25,9 +25,10 @@ import org.jeecg.modules.system.model.TreeModel;
import org.jeecg.modules.system.service.*;
import org.jeecg.modules.system.util.PermissionDataUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;
@ -67,9 +68,9 @@ public class SysPermissionController {
@Autowired
private ISysRoleIndexService sysRoleIndexService;
@Autowired
private ShiroRealm shiroRealm;
private JeecgPermissionService jeecgPermissionService;
/**
* 子菜单
@ -245,7 +246,7 @@ public class SysPermissionController {
Result<JSONObject> result = new Result<JSONObject>();
try {
//直接获取当前用户不适用前端token
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser loginUser = SecureUtil.currentUser();
if (oConvertUtils.isEmpty(loginUser)) {
return Result.error("请登录系统!");
}
@ -357,7 +358,7 @@ public class SysPermissionController {
public Result<?> getPermCode() {
try {
// 直接获取当前用户
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser loginUser = SecureUtil.currentUser();
if (oConvertUtils.isEmpty(loginUser)) {
return Result.error("请登录系统!");
}
@ -398,7 +399,7 @@ public class SysPermissionController {
* @param permission
* @return
*/
@RequiresPermissions("system:permission:add")
@PreAuthorize("@jps.requiresPermissions('system:permission:add')")
@RequestMapping(value = "/add", method = RequestMethod.POST)
public Result<SysPermission> add(@RequestBody SysPermission permission) {
Result<SysPermission> result = new Result<SysPermission>();
@ -418,7 +419,7 @@ public class SysPermissionController {
* @param permission
* @return
*/
@RequiresPermissions("system:permission:edit")
@PreAuthorize("@jps.requiresPermissions('system:permission:edit')")
@RequestMapping(value = "/edit", method = { RequestMethod.PUT, RequestMethod.POST })
public Result<SysPermission> edit(@RequestBody SysPermission permission) {
Result<SysPermission> result = new Result<>();
@ -460,7 +461,7 @@ public class SysPermissionController {
* @param id
* @return
*/
@RequiresPermissions("system:permission:delete")
@PreAuthorize("@jps.requiresPermissions('system:permission:delete')")
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
public Result<SysPermission> delete(@RequestParam(name = "id", required = true) String id) {
Result<SysPermission> result = new Result<>();
@ -479,7 +480,7 @@ public class SysPermissionController {
* @param ids
* @return
*/
@RequiresPermissions("system:permission:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('system:permission:deleteBatch')")
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
public Result<SysPermission> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
Result<SysPermission> result = new Result<>();
@ -587,7 +588,7 @@ public class SysPermissionController {
* @return
*/
@RequestMapping(value = "/saveRolePermission", method = RequestMethod.POST)
@RequiresPermissions("system:permission:saveRole")
@PreAuthorize("@jps.requiresPermissions('system:permission:saveRole')")
public Result<String> saveRolePermission(@RequestBody JSONObject json) {
long start = System.currentTimeMillis();
Result<String> result = new Result<>();
@ -597,21 +598,13 @@ public class SysPermissionController {
String lastPermissionIds = json.getString("lastpermissionIds");
this.sysRolePermissionService.saveRolePermission(roleId, permissionIds, lastPermissionIds);
//update-begin---author:wangshuai ---date:20220316 for[VUEN-234]用户管理角色授权添加敏感日志------------
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser loginUser = SecureUtil.currentUser();
baseCommonService.addLog("修改角色ID: "+roleId+" 的权限配置,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
//update-end---author:wangshuai ---date:20220316 for[VUEN-234]用户管理角色授权添加敏感日志------------
// 清除权限缓存
jeecgPermissionService.clearCache();
result.success("保存成功!");
log.info("======角色授权成功=====耗时:" + (System.currentTimeMillis() - start) + "毫秒");
//update-begin---author:scott ---date:2024-06-18 for【TV360X-1320】分配权限必须退出重新登录才生效造成很多用户困扰---
// 获取当前用户的Subject对象
Subject currentUser = SecurityUtils.getSubject();
// 清除当前用户的授权缓存信息
if (currentUser.isAuthenticated()) {
shiroRealm.clearCache(currentUser.getPrincipals());
}
//update-end---author:scott ---date::2024-06-18 for【TV360X-1320】分配权限必须退出重新登录才生效造成很多用户困扰---
} catch (Exception e) {
result.error500("授权失败!");
log.error(e.getMessage(), e);
@ -925,7 +918,7 @@ public class SysPermissionController {
* @param sysPermissionDataRule
* @return
*/
@RequiresPermissions("system:permission:addRule")
@PreAuthorize("@jps.requiresPermissions('system:permission:addRule')")
@RequestMapping(value = "/addPermissionRule", method = RequestMethod.POST)
public Result<SysPermissionDataRule> addPermissionRule(@RequestBody SysPermissionDataRule sysPermissionDataRule) {
Result<SysPermissionDataRule> result = new Result<SysPermissionDataRule>();
@ -940,7 +933,7 @@ public class SysPermissionController {
return result;
}
@RequiresPermissions("system:permission:editRule")
@PreAuthorize("@jps.requiresPermissions('system:permission:editRule')")
@RequestMapping(value = "/editPermissionRule", method = { RequestMethod.PUT, RequestMethod.POST })
public Result<SysPermissionDataRule> editPermissionRule(@RequestBody SysPermissionDataRule sysPermissionDataRule) {
Result<SysPermissionDataRule> result = new Result<SysPermissionDataRule>();
@ -960,7 +953,7 @@ public class SysPermissionController {
* @param id
* @return
*/
@RequiresPermissions("system:permission:deleteRule")
@PreAuthorize("@jps.requiresPermissions('system:permission:deleteRule')")
@RequestMapping(value = "/deletePermissionRule", method = RequestMethod.DELETE)
public Result<SysPermissionDataRule> deletePermissionRule(@RequestParam(name = "id", required = true) String id) {
Result<SysPermissionDataRule> result = new Result<SysPermissionDataRule>();
@ -1017,7 +1010,7 @@ public class SysPermissionController {
* @return
*/
@RequestMapping(value = "/saveDepartPermission", method = RequestMethod.POST)
@RequiresPermissions("system:permission:saveDepart")
@PreAuthorize("@jps.requiresPermissions('system:permission:saveDepart')")
public Result<String> saveDepartPermission(@RequestBody JSONObject json) {
long start = System.currentTimeMillis();
Result<String> result = new Result<>();

View File

@ -8,7 +8,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.config.TenantContext;
@ -18,6 +17,7 @@ import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.ImportExcelUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.system.entity.SysPosition;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysPositionService;
@ -29,6 +29,7 @@ import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@ -242,7 +243,7 @@ public class SysPositionController {
//Step.2 AutoPoi 导出Excel
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
List<SysPosition> pageList = sysPositionService.list(queryWrapper);
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "职务表列表");
mv.addObject(NormalExcelConstants.CLASS, SysPosition.class);

View File

@ -1,21 +1,19 @@
package org.jeecg.modules.system.controller;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.base.BaseMap;
import org.jeecg.common.config.TenantContext;
@ -25,6 +23,7 @@ import org.jeecg.common.modules.redis.client.JeecgRedisClient;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.*;
import org.jeecg.modules.system.model.TreeModel;
@ -36,6 +35,8 @@ import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@ -48,7 +49,6 @@ import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import org.jeecg.common.system.vo.LoginUser;
import org.apache.shiro.SecurityUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -96,7 +96,7 @@ public class SysRoleController {
* @param req
* @return
*/
@RequiresPermissions("system:role:list")
@PreAuthorize("@jps.requiresPermissions('system:role:list')")
@RequestMapping(value = "/list", method = RequestMethod.GET)
public Result<IPage<SysRole>> queryPageList(SysRole role,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@ -146,7 +146,7 @@ public class SysRoleController {
* @return
*/
@RequestMapping(value = "/add", method = RequestMethod.POST)
@RequiresPermissions("system:role:add")
@PreAuthorize("@jps.requiresPermissions('system:role:add')")
public Result<SysRole> add(@RequestBody SysRole role) {
Result<SysRole> result = new Result<SysRole>();
try {
@ -171,7 +171,7 @@ public class SysRoleController {
* @param role
* @return
*/
@RequiresPermissions("system:role:edit")
@PreAuthorize("@jps.requiresPermissions('system:role:edit')")
@RequestMapping(value = "/edit",method = {RequestMethod.PUT,RequestMethod.POST})
public Result<SysRole> edit(@RequestBody SysRole role) {
Result<SysRole> result = new Result<SysRole>();
@ -185,7 +185,7 @@ public class SysRoleController {
//如果是saas隔离的情况下判断当前租户id是否是当前租户下的
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
//获取当前用户
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
Integer tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
String username = "admin";
if (!tenantId.equals(role.getTenantId()) && !username.equals(sysUser.getUsername())) {
@ -208,13 +208,13 @@ public class SysRoleController {
* @param id
* @return
*/
@RequiresPermissions("system:role:delete")
@PreAuthorize("@jps.requiresPermissions('system:role:delete')")
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
//如果是saas隔离的情况下判断当前租户id是否是当前租户下的
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){
//获取当前用户
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
int tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
Long getRoleCount = sysRoleService.getRoleCountByTenantId(id, tenantId);
String username = "admin";
@ -239,7 +239,7 @@ public class SysRoleController {
* @param ids
* @return
*/
@RequiresPermissions("system:role:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('system:role:deleteBatch')")
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
public Result<SysRole> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
baseCommonService.addLog("删除角色操作角色ids" + ids, CommonConstant.LOG_TYPE_2, CommonConstant.OPERATE_TYPE_4);
@ -251,7 +251,7 @@ public class SysRoleController {
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){
int tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
String[] roleIds = ids.split(SymbolConstant.COMMA);
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
String username = "admin";
for (String id:roleIds) {
Long getRoleCount = sysRoleService.getRoleCountByTenantId(id, tenantId);
@ -318,7 +318,7 @@ public class SysRoleController {
*
* @return
*/
@RequiresPermissions("system:role:queryallNoByTenant")
@PreAuthorize("@jps.requiresPermissions('system:role:queryallNoByTenant')")
@RequestMapping(value = "/queryallNoByTenant", method = RequestMethod.GET)
public Result<List<SysRole>> queryallNoByTenant() {
Result<List<SysRole>> result = new Result<>();
@ -394,7 +394,7 @@ public class SysRoleController {
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME,"角色列表");
mv.addObject(NormalExcelConstants.CLASS,SysRole.class);
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
mv.addObject(NormalExcelConstants.PARAMS,new ExportParams("角色列表数据","导出人:"+user.getRealname(),"导出信息"));
mv.addObject(NormalExcelConstants.DATA_LIST,pageList);
return mv;

View File

@ -8,8 +8,6 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.aspect.annotation.AutoLog;
@ -23,6 +21,7 @@ import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
@ -68,7 +67,7 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
* @param sysRoleIndex
* @return
*/
@RequiresPermissions("system:roleindex:add")
@PreAuthorize("@jps.requiresPermissions('system:roleindex:add')")
@AutoLog(value = "角色首页配置-添加")
@Operation(summary = "角色首页配置-添加")
@PostMapping(value = "/add")
@ -84,7 +83,7 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
* @param sysRoleIndex
* @return
*/
@RequiresPermissions("system:roleindex:edit")
@PreAuthorize("@jps.requiresPermissions('system:roleindex:edit')")
@AutoLog(value = "角色首页配置-编辑")
@Operation(summary = "角色首页配置-编辑")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
@ -186,7 +185,7 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
/**
* 更新默认首页配置
*/
@RequiresPermissions("system:permission:setDefIndex")
@PreAuthorize("@jps.requiresPermissions('system:permission:setDefIndex')")
@PutMapping("/updateDefIndex")
public Result<?> updateDefIndex(
@RequestParam("url") String url,

View File

@ -6,7 +6,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.annotation.RequiresRoles;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
@ -15,6 +14,7 @@ import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.modules.system.entity.SysTableWhiteList;
import org.jeecg.modules.system.service.ISysTableWhiteListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
/**
@ -41,8 +41,8 @@ public class SysTableWhiteListController extends JeecgController<SysTableWhiteLi
* @param req
* @return
*/
@RequiresRoles("admin")
@GetMapping(value = "/list")
@PreAuthorize("@jps.requiresRoles('admin')")
public Result<?> queryPageList(
SysTableWhiteList sysTableWhiteList,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@ -63,7 +63,7 @@ public class SysTableWhiteListController extends JeecgController<SysTableWhiteLi
*/
@AutoLog(value = "系统表白名单-添加")
@Operation(summary = "系统表白名单-添加")
@RequiresRoles("admin")
@PreAuthorize("@jps.requiresRoles('admin')")
@PostMapping(value = "/add")
public Result<?> add(@RequestBody SysTableWhiteList sysTableWhiteList) {
if (sysTableWhiteListService.add(sysTableWhiteList)) {
@ -81,7 +81,7 @@ public class SysTableWhiteListController extends JeecgController<SysTableWhiteLi
*/
@AutoLog(value = "系统表白名单-编辑")
@Operation(summary = "系统表白名单-编辑")
@RequiresRoles("admin")
@PreAuthorize("@jps.requiresRoles('admin')")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
public Result<?> edit(@RequestBody SysTableWhiteList sysTableWhiteList) {
if (sysTableWhiteListService.edit(sysTableWhiteList)) {
@ -99,7 +99,7 @@ public class SysTableWhiteListController extends JeecgController<SysTableWhiteLi
*/
@AutoLog(value = "系统表白名单-通过id删除")
@Operation(summary = "系统表白名单-通过id删除")
@RequiresRoles("admin")
@PreAuthorize("@jps.requiresRoles('admin')")
@DeleteMapping(value = "/delete")
public Result<?> delete(@RequestParam(name = "id") String id) {
if (sysTableWhiteListService.deleteByIds(id)) {
@ -117,7 +117,7 @@ public class SysTableWhiteListController extends JeecgController<SysTableWhiteLi
*/
@AutoLog(value = "系统表白名单-批量删除")
@Operation(summary = "系统表白名单-批量删除")
@RequiresRoles("admin")
@PreAuthorize("@jps.requiresRoles('admin')")
@DeleteMapping(value = "/deleteBatch")
public Result<?> deleteBatch(@RequestParam(name = "ids") String ids) {
if (sysTableWhiteListService.deleteByIds(ids)) {
@ -135,7 +135,7 @@ public class SysTableWhiteListController extends JeecgController<SysTableWhiteLi
*/
@AutoLog(value = "系统表白名单-通过id查询")
@Operation(summary = "系统表白名单-通过id查询")
@RequiresRoles("admin")
@PreAuthorize("@jps.requiresRoles('admin')")
@GetMapping(value = "/queryById")
public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
SysTableWhiteList sysTableWhiteList = sysTableWhiteListService.getById(id);

View File

@ -3,13 +3,13 @@ package org.jeecg.modules.system.controller;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.PermissionData;
import org.jeecg.common.config.TenantContext;
@ -21,6 +21,7 @@ import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.*;
import org.jeecg.modules.system.service.ISysTenantPackService;
@ -34,6 +35,8 @@ import org.jeecg.modules.system.vo.tenant.TenantPackModel;
import org.jeecg.modules.system.vo.tenant.TenantPackUser;
import org.jeecg.modules.system.vo.tenant.TenantPackUserCount;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
@ -74,7 +77,7 @@ public class SysTenantController {
* @param req
* @return
*/
@RequiresPermissions("system:tenant:list")
@PreAuthorize("@jps.requiresPermissions('system:tenant:list')")
@PermissionData(pageComponent = "system/TenantList")
@RequestMapping(value = "/list", method = RequestMethod.GET)
public Result<IPage<SysTenant>> queryPageList(SysTenant sysTenant,@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@ -113,7 +116,7 @@ public class SysTenantController {
* @return
*/
@GetMapping("/recycleBinPageList")
@RequiresPermissions("system:tenant:recycleBinPageList")
@PreAuthorize("@jps.requiresPermissions('system:tenant:recycleBinPageList')")
public Result<IPage<SysTenant>> recycleBinPageList(SysTenant sysTenant,@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,HttpServletRequest req){
Result<IPage<SysTenant>> result = new Result<IPage<SysTenant>>();
@ -129,7 +132,7 @@ public class SysTenantController {
* @param
* @return
*/
@RequiresPermissions("system:tenant:add")
@PreAuthorize("@jps.requiresPermissions('system:tenant:add')")
@RequestMapping(value = "/add", method = RequestMethod.POST)
public Result<SysTenant> add(@RequestBody SysTenant sysTenant) {
Result<SysTenant> result = new Result();
@ -153,7 +156,7 @@ public class SysTenantController {
* @param
* @return
*/
@RequiresPermissions("system:tenant:edit")
@PreAuthorize("@jps.requiresPermissions('system:tenant:edit')")
@RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
public Result<SysTenant> edit(@RequestBody SysTenant tenant) {
Result<SysTenant> result = new Result();
@ -176,14 +179,14 @@ public class SysTenantController {
* @param id
* @return
*/
@RequiresPermissions("system:tenant:delete")
@PreAuthorize("@jps.requiresPermissions('system:tenant:delete')")
@RequestMapping(value = "/delete", method ={RequestMethod.DELETE, RequestMethod.POST})
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
//------------------------------------------------------------------
//如果是saas隔离的情况下判断当前租户id是否是当前租户下的
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
//获取当前用户
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();;
SysTenant sysTenant = sysTenantService.getById(id);
String username = "admin";
@ -204,7 +207,7 @@ public class SysTenantController {
* @param ids
* @return
*/
@RequiresPermissions("system:tenant:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('system:tenant:deleteBatch')")
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
Result<?> result = new Result<>();
@ -219,7 +222,7 @@ public class SysTenantController {
//如果是saas隔离的情况下判断当前租户id是否是当前租户下的
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
//获取当前用户
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
SysTenant sysTenant = sysTenantService.getById(id);
String username = "admin";
@ -254,7 +257,7 @@ public class SysTenantController {
}
//------------------------------------------------------------------------------------------------
//获取登录用户信息
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
//是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】, admin给特权可以管理所有租户
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && !"admin".equals(sysUser.getUsername())){
Integer loginSessionTenant = oConvertUtils.getInt(TenantContext.getTenant());
@ -279,7 +282,7 @@ public class SysTenantController {
* 查询有效的 租户数据
* @return
*/
@RequiresPermissions("system:tenant:queryList")
@PreAuthorize("@jps.requiresPermissions('system:tenant:queryList')")
@RequestMapping(value = "/queryList", method = RequestMethod.GET)
public Result<List<SysTenant>> queryList(@RequestParam(name="ids",required=false) String ids) {
Result<List<SysTenant>> result = new Result<List<SysTenant>>();
@ -305,7 +308,7 @@ public class SysTenantController {
* @return
*/
@GetMapping(value = "/packList")
@RequiresPermissions("system:tenant:packList")
@PreAuthorize("@jps.requiresPermissions('system:tenant:packList')")
public Result<IPage<SysTenantPack>> queryPackPageList(SysTenantPack sysTenantPack,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
@ -327,7 +330,7 @@ public class SysTenantController {
* @return
*/
@PostMapping(value = "/addPackPermission")
@RequiresPermissions("system:tenant:add:pack")
@PreAuthorize("@jps.requiresPermissions('system:tenant:add:pack')")
public Result<String> addPackPermission(@RequestBody SysTenantPack sysTenantPack) {
sysTenantPackService.addPackPermission(sysTenantPack);
return Result.ok("创建租户产品包成功");
@ -340,7 +343,7 @@ public class SysTenantController {
* @return
*/
@PutMapping(value = "/editPackPermission")
@RequiresPermissions("system:tenant:edit:pack")
@PreAuthorize("@jps.requiresPermissions('system:tenant:edit:pack')")
public Result<String> editPackPermission(@RequestBody SysTenantPack sysTenantPack) {
sysTenantPackService.editPackPermission(sysTenantPack);
return Result.ok("修改租户产品包成功");
@ -353,7 +356,7 @@ public class SysTenantController {
* @return
*/
@DeleteMapping("/deleteTenantPack")
@RequiresPermissions("system:tenant:delete:pack")
@PreAuthorize("@jps.requiresPermissions('system:tenant:delete:pack')")
public Result<String> deleteTenantPack(@RequestParam(value = "ids") String ids) {
sysTenantPackService.deleteTenantPack(ids);
return Result.ok("删除租户产品包成功");
@ -370,7 +373,7 @@ public class SysTenantController {
public Result<Map<String,Object>> getCurrentUserTenant() {
Result<Map<String,Object>> result = new Result<Map<String,Object>>();
try {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
//update-begin---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
List<Integer> tenantIdList = relationService.getTenantIdsByUserId(sysUser.getId());
Map<String,Object> map = new HashMap(5);
@ -396,7 +399,7 @@ public class SysTenantController {
* @return
*/
@PutMapping("/invitationUserJoin")
@RequiresPermissions("system:tenant:invitation:user")
@PreAuthorize("@jps.requiresPermissions('system:tenant:invitation:user')")
public Result<String> invitationUserJoin(@RequestParam("ids") String ids,@RequestParam("phone") String phone){
sysTenantService.invitationUserJoin(ids,phone);
return Result.ok("邀请用户成功");
@ -411,7 +414,7 @@ public class SysTenantController {
* @return
*/
@RequestMapping(value = "/getTenantUserList", method = RequestMethod.GET)
@RequiresPermissions("system:tenant:user:list")
@PreAuthorize("@jps.requiresPermissions('system:tenant:user:list')")
public Result<IPage<SysUser>> getTenantUserList(SysUser user,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
@ -432,12 +435,12 @@ public class SysTenantController {
* @return
*/
@PutMapping("/leaveTenant")
@RequiresPermissions("system:tenant:leave")
@PreAuthorize("@jps.requiresPermissions('system:tenant:leave')")
public Result<String> leaveTenant(@RequestParam("userIds") String userIds,
@RequestParam("tenantId") String tenantId){
Result<String> result = new Result<>();
//是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && !"admin".equals(sysUser.getUsername())){
Integer loginSessionTenant = oConvertUtils.getInt(TenantContext.getTenant());
if(loginSessionTenant!=null && !loginSessionTenant.equals(Integer.valueOf(tenantId))){
@ -483,7 +486,7 @@ public class SysTenantController {
@PostMapping("/saveTenantJoinUser")
public Result<Integer> saveTenantJoinUser(@RequestBody SysTenant sysTenant){
Result<Integer> result = new Result<>();
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
Integer tenantId = sysTenantService.saveTenantJoinUser(sysTenant, sysUser.getId());
result.setSuccess(true);
result.setMessage("创建成功");
@ -497,7 +500,7 @@ public class SysTenantController {
*/
@PostMapping("/joinTenantByHouseNumber")
public Result<Integer> joinTenantByHouseNumber(@RequestBody SysTenant sysTenant){
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
Integer tenantId = sysTenantService.joinTenantByHouseNumber(sysTenant, sysUser.getId());
Result<Integer> result = new Result<>();
if(tenantId != 0){
@ -532,7 +535,7 @@ public class SysTenantController {
SysUser user,
HttpServletRequest req) {
Page<SysUserTenantVo> page = new Page<SysUserTenantVo>(pageNo, pageSize);
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
String tenantId = oConvertUtils.getString(TenantContext.getTenant(), "0");
IPage<SysUserTenantVo> list = relationService.getUserTenantPageList(page, Arrays.asList(userTenantStatus.split(SymbolConstant.COMMA)), user, Integer.valueOf(tenantId));
return Result.ok(list);
@ -547,7 +550,7 @@ public class SysTenantController {
@GetMapping("/getTenantListByUserId")
//@RequiresPermissions("system:tenant:getTenantListByUserId")
public Result<List<SysUserTenantVo>> getTenantListByUserId(@RequestParam(name = "userTenantStatus", required = false) String userTenantStatus) {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
List<String> list = null;
if (oConvertUtils.isNotEmpty(userTenantStatus)) {
list = Arrays.asList(userTenantStatus.split(SymbolConstant.COMMA));
@ -580,7 +583,7 @@ public class SysTenantController {
@PutMapping("/cancelTenant")
//@RequiresPermissions("system:tenant:cancelTenant")
public Result<String> cancelTenant(@RequestBody SysTenant sysTenant,HttpServletRequest request) {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
SysTenant tenant = sysTenantService.getById(sysTenant.getId());
if (null == tenant) {
return Result.error("未找到当前租户信息");
@ -623,7 +626,7 @@ public class SysTenantController {
*/
@PutMapping("/cancelApplyTenant")
public Result<String> cancelApplyTenant(@RequestParam("tenantId") String tenantId){
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
sysTenantService.leaveTenant(sysUser.getId(),tenantId);
return Result.ok("取消申请成功");
}
@ -636,7 +639,7 @@ public class SysTenantController {
* @return
*/
@DeleteMapping("/deleteLogicDeleted")
@RequiresPermissions("system:tenant:deleteTenantLogic")
@PreAuthorize("@jps.requiresPermissions('system:tenant:deleteTenantLogic')")
public Result<String> deleteTenantLogic(@RequestParam("ids") String ids){
sysTenantService.deleteTenantLogic(ids);
return Result.ok("彻底删除成功");
@ -648,7 +651,7 @@ public class SysTenantController {
* @return
*/
@PutMapping("/revertTenantLogic")
@RequiresPermissions("system:tenant:revertTenantLogic")
@PreAuthorize("@jps.requiresPermissions('system:tenant:revertTenantLogic')")
public Result<String> revertTenantLogic(@RequestParam("ids") String ids){
sysTenantService.revertTenantLogic(ids);
return Result.ok("还原成功");
@ -662,7 +665,7 @@ public class SysTenantController {
*/
@DeleteMapping("/exitUserTenant")
public Result<String> exitUserTenant(@RequestBody SysTenant sysTenant,HttpServletRequest request){
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
//验证用户是否已存在
Integer count = relationService.userTenantIzExist(sysUser.getId(),sysTenant.getId());
if (count == 0) {
@ -887,7 +890,7 @@ public class SysTenantController {
public Result<IPage<SysTenant>> getTenantPageListByUserId(SysUserTenantVo sysUserTenantVo,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
List<String> list = null;
String userTenantStatus = sysUserTenantVo.getUserTenantStatus();
if (oConvertUtils.isNotEmpty(userTenantStatus)) {
@ -905,7 +908,7 @@ public class SysTenantController {
public Result<String> agreeOrRefuseJoinTenant(@RequestParam("tenantId") Integer tenantId,
@RequestParam("status") String status){
//是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
String userId = sysUser.getId();
SysTenant tenant = sysTenantService.getById(tenantId);
if(null == tenant){

View File

@ -10,11 +10,11 @@ import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.system.entity.SysUserAgent;
import org.jeecg.modules.system.service.ISysUserAgentService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
@ -216,7 +216,7 @@ public class SysUserAgentController {
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "用户代理人设置列表");
mv.addObject(NormalExcelConstants.CLASS, SysUserAgent.class);
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
ExportParams exportParams = new ExportParams("用户代理人设置列表数据", "导出人:"+user.getRealname(), "导出信息");
exportParams.setImageBasePath(upLoadPath);
mv.addObject(NormalExcelConstants.PARAMS, exportParams);

View File

@ -11,15 +11,15 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.PermissionData;
import org.jeecg.common.base.BaseMap;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.common.modules.redis.client.JeecgRedisClient;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.util.JwtUtil;
@ -42,6 +42,7 @@ import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@ -142,7 +143,7 @@ public class SysUserController {
* @param req
* @return
*/
@RequiresPermissions("system:user:listAll")
@PreAuthorize("@jps.requiresPermissions('system:user:listAll')")
@RequestMapping(value = "/listAll", method = RequestMethod.GET)
public Result<IPage<SysUser>> queryAllPageList(SysUser user, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
@ -150,7 +151,7 @@ public class SysUserController {
return sysUserService.queryPageList(req, queryWrapper, pageSize, pageNo);
}
@RequiresPermissions("system:user:add")
@PreAuthorize("@jps.requiresPermissions('system:user:add')")
@RequestMapping(value = "/add", method = RequestMethod.POST)
public Result<SysUser> add(@RequestBody JSONObject jsonObject) {
Result<SysUser> result = new Result<SysUser>();
@ -180,7 +181,7 @@ public class SysUserController {
return result;
}
@RequiresPermissions("system:user:edit")
@PreAuthorize("@jps.requiresPermissions('system:user:edit')")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<SysUser> edit(@RequestBody JSONObject jsonObject) {
Result<SysUser> result = new Result<SysUser>();
@ -218,7 +219,7 @@ public class SysUserController {
/**
* 删除用户
*/
@RequiresPermissions("system:user:delete")
@PreAuthorize("@jps.requiresPermissions('system:user:delete')")
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
baseCommonService.addLog("删除用户id " +id ,CommonConstant.LOG_TYPE_2, 3);
@ -229,7 +230,7 @@ public class SysUserController {
/**
* 批量删除用户
*/
@RequiresPermissions("system:user:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('system:user:deleteBatch')")
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
baseCommonService.addLog("批量删除用户, ids " +ids ,CommonConstant.LOG_TYPE_2, 3);
@ -242,7 +243,7 @@ public class SysUserController {
* @param jsonObject
* @return
*/
@RequiresPermissions("system:user:frozenBatch")
@PreAuthorize("@jps.requiresPermissions('system:user:frozenBatch')")
@RequestMapping(value = "/frozenBatch", method = RequestMethod.PUT)
public Result<SysUser> frozenBatch(@RequestBody JSONObject jsonObject) {
Result<SysUser> result = new Result<SysUser>();
@ -267,7 +268,7 @@ public class SysUserController {
}
@RequiresPermissions("system:user:queryById")
@PreAuthorize("@jps.requiresPermissions('system:user:queryById')")
@RequestMapping(value = "/queryById", method = RequestMethod.GET)
public Result<SysUser> queryById(@RequestParam(name = "id", required = true) String id) {
Result<SysUser> result = new Result<SysUser>();
@ -281,7 +282,7 @@ public class SysUserController {
return result;
}
@RequiresPermissions("system:user:queryUserRole")
@PreAuthorize("@jps.requiresPermissions('system:user:queryUserRole')")
@RequestMapping(value = "/queryUserRole", method = RequestMethod.GET)
public Result<List<String>> queryUserRole(@RequestParam(name = "userid", required = true) String userid) {
Result<List<String>> result = new Result<>();
@ -334,7 +335,7 @@ public class SysUserController {
/**
* 修改密码
*/
@RequiresPermissions("system:user:changepwd")
@PreAuthorize("@jps.requiresPermissions('system:user:changepwd')")
@RequestMapping(value = "/changePassword", method = RequestMethod.PUT)
public Result<?> changePassword(@RequestBody SysUser sysUser) {
SysUser u = this.sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, sysUser.getUsername()));
@ -343,7 +344,7 @@ public class SysUserController {
}
sysUser.setId(u.getId());
//update-begin---author:wangshuai ---date:20220316 for[VUEN-234]修改密码添加敏感日志------------
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser loginUser = SecureUtil.currentUser();
baseCommonService.addLog("修改用户 "+sysUser.getUsername()+" 的密码,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
//update-end---author:wangshuai ---date:20220316 for[VUEN-234]修改密码添加敏感日志------------
return sysUserService.changePassword(sysUser);
@ -458,7 +459,7 @@ public class SysUserController {
* @param request
* @param sysUser
*/
@RequiresPermissions("system:user:export")
@PreAuthorize("@jps.requiresPermissions('system:user:export')")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(SysUser sysUser,HttpServletRequest request) {
// Step.1 组装查询条件
@ -476,7 +477,7 @@ public class SysUserController {
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "用户列表");
mv.addObject(NormalExcelConstants.CLASS, SysUser.class);
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
ExportParams exportParams = new ExportParams("用户列表数据", "导出人:"+user.getRealname(), "导出信息");
exportParams.setImageBasePath(upLoadPath);
mv.addObject(NormalExcelConstants.PARAMS, exportParams);
@ -491,7 +492,7 @@ public class SysUserController {
* @param response
* @return
*/
@RequiresPermissions("system:user:import")
@PreAuthorize("@jps.requiresPermissions('system:user:import')")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response)throws IOException {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
@ -605,14 +606,14 @@ public class SysUserController {
/**
* 首页用户重置密码
*/
@RequiresPermissions("system:user:updatepwd")
@PreAuthorize("@jps.requiresPermissions('system:user:updatepwd')")
@RequestMapping(value = "/updatePassword", method = RequestMethod.PUT)
public Result<?> updatePassword(@RequestBody JSONObject json) {
String username = json.getString("username");
String oldpassword = json.getString("oldpassword");
String password = json.getString("password");
String confirmpassword = json.getString("confirmpassword");
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
if(!sysUser.getUsername().equals(username)){
return Result.error("只允许修改自己的密码!");
}
@ -621,7 +622,7 @@ public class SysUserController {
return Result.error("用户不存在!");
}
//update-begin---author:wangshuai ---date:20220316 for[VUEN-234]修改密码添加敏感日志------------
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser loginUser = SecureUtil.currentUser();
baseCommonService.addLog("修改密码username " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
//update-end---author:wangshuai ---date:20220316 for[VUEN-234]修改密码添加敏感日志------------
return sysUserService.resetPassword(username,oldpassword,password,confirmpassword);
@ -646,7 +647,7 @@ public class SysUserController {
* @param
* @return
*/
@RequiresPermissions("system:user:addUserRole")
@PreAuthorize("@jps.requiresPermissions('system:user:addUserRole')")
@RequestMapping(value = "/addSysUserRole", method = RequestMethod.POST)
public Result<String> addSysUserRole(@RequestBody SysUserRoleVO sysUserRoleVO) {
Result<String> result = new Result<String>();
@ -678,7 +679,7 @@ public class SysUserController {
* @param
* @return
*/
@RequiresPermissions("system:user:deleteRole")
@PreAuthorize("@jps.requiresPermissions('system:user:deleteRole')")
@RequestMapping(value = "/deleteUserRole", method = RequestMethod.DELETE)
public Result<SysUserRole> deleteUserRole(@RequestParam(name="roleId") String roleId,
@RequestParam(name="userId",required=true) String userId
@ -702,7 +703,7 @@ public class SysUserController {
* @param
* @return
*/
@RequiresPermissions("system:user:deleteRoleBatch")
@PreAuthorize("@jps.requiresPermissions('system:user:deleteRoleBatch')")
@RequestMapping(value = "/deleteUserRoleBatch", method = RequestMethod.DELETE)
public Result<SysUserRole> deleteUserRoleBatch(
@RequestParam(name="roleId") String roleId,
@ -734,7 +735,7 @@ public class SysUserController {
List<String> subDepids = new ArrayList<>();
//部门id为空时查询我的部门下所有用户
if(oConvertUtils.isEmpty(depId)){
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
int userIdentity = user.getUserIdentity() != null?user.getUserIdentity():CommonConstant.USER_IDENTITY_1;
if(oConvertUtils.isNotEmpty(userIdentity) && userIdentity == CommonConstant.USER_IDENTITY_2 ){
subDepids = sysDepartService.getMySubDepIdsByDepId(user.getDepartIds());
@ -833,7 +834,7 @@ public class SysUserController {
/**
* 给指定部门添加对应的用户
*/
@RequiresPermissions("system:user:editDepartWithUser")
@PreAuthorize("@jps.requiresPermissions('system:user:editDepartWithUser')")
@RequestMapping(value = "/editSysDepartWithUser", method = RequestMethod.POST)
public Result<String> editSysDepartWithUser(@RequestBody SysDepartUsersVO sysDepartUsersVO) {
Result<String> result = new Result<String>();
@ -862,7 +863,7 @@ public class SysUserController {
/**
* 删除指定机构的用户关系
*/
@RequiresPermissions("system:user:deleteUserInDepart")
@PreAuthorize("@jps.requiresPermissions('system:user:deleteUserInDepart')")
@RequestMapping(value = "/deleteUserInDepart", method = RequestMethod.DELETE)
public Result<SysUserDepart> deleteUserInDepart(@RequestParam(name="depId") String depId,
@RequestParam(name="userId",required=true) String userId
@ -894,7 +895,7 @@ public class SysUserController {
/**
* 批量删除指定机构的用户关系
*/
@RequiresPermissions("system:user:deleteUserInDepartBatch")
@PreAuthorize("@jps.requiresPermissions('system:user:deleteUserInDepartBatch')")
@RequestMapping(value = "/deleteUserInDepartBatch", method = RequestMethod.DELETE)
public Result<SysUserDepart> deleteUserInDepartBatch(
@RequestParam(name="depId") String depId,
@ -923,7 +924,7 @@ public class SysUserController {
public Result<Map<String,Object>> getCurrentUserDeparts() {
Result<Map<String,Object>> result = new Result<Map<String,Object>>();
try {
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
List<SysDepart> list = this.sysDepartService.queryUserDeparts(sysUser.getId());
Map<String,Object> map = new HashMap(5);
map.put("list", list);
@ -1271,7 +1272,7 @@ public class SysUserController {
* @param userIds 被删除的用户ID多个id用半角逗号分割
* @return
*/
@RequiresPermissions("system:user:deleteRecycleBin")
@PreAuthorize("@jps.requiresPermissions('system:user:deleteRecycleBin')")
@RequestMapping(value = "/deleteRecycleBin", method = RequestMethod.DELETE)
public Result deleteRecycleBin(@RequestParam("userIds") String userIds) {
if (StringUtils.isNotBlank(userIds)) {
@ -1286,7 +1287,7 @@ public class SysUserController {
* @param jsonObject
* @return
*/
@RequiresRoles({"admin"})
@PreAuthorize("@jps.requiresRoles('admin')")
@RequestMapping(value = "/appEdit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<SysUser> appEdit(HttpServletRequest request,@RequestBody JSONObject jsonObject) {
Result<SysUser> result = new Result<SysUser>();
@ -1677,7 +1678,7 @@ public class SysUserController {
* @return
*/
@PostMapping("/login/setting/userEdit")
@RequiresPermissions("system:user:setting:edit")
@PreAuthorize("@jps.requiresPermissions('system:user:setting:edit')")
public Result<String> userEdit(@RequestBody SysUser sysUser, HttpServletRequest request) {
String username = JwtUtil.getUserNameByToken(request);
SysUser user = sysUserService.getById(sysUser.getId());
@ -1789,7 +1790,7 @@ public class SysUserController {
public Result<?> changeLoginTenantId(@RequestBody SysUser sysUser){
Result<String> result = new Result<>();
Integer tenantId = sysUser.getLoginTenantId();
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser loginUser = SecureUtil.currentUser();
String userId = loginUser.getId();
// 判断 指定的租户ID是不是当前登录用户的租户

View File

@ -3,7 +3,6 @@ package org.jeecg.modules.system.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
@ -17,7 +16,11 @@ import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
import org.jeecg.modules.system.vo.SysUserOnlineVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
@ -48,6 +51,10 @@ public class SysUserOnlineController {
@Resource
private BaseCommonService baseCommonService;
@Autowired
private OAuth2AuthorizationService authorizationService;
@Autowired
private CacheManager cacheManager;
@RequestMapping(value = "/list", method = RequestMethod.GET)
public Result<Page<SysUserOnlineVO>> list(@RequestParam(name="username", required=false) String username,
@ -120,8 +127,13 @@ public class SysUserOnlineController {
redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
//清空用户的缓存信息包括部门信息例如sys:cache:user::<username>
redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
//调用shiro的logout
SecurityUtils.getSubject().logout();
//调用logout
OAuth2Authorization authorization = authorizationService.findByToken(online.getToken(), OAuth2TokenType.ACCESS_TOKEN);
// 清空用户信息
cacheManager.getCache("user_details").evict(authorization.getPrincipalName());
// 清空access token
authorizationService.remove(authorization);
return Result.ok("退出登录成功!");
}else {
return Result.error("Token无效!");

View File

@ -1,11 +1,11 @@
package org.jeecg.modules.system.controller;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jeecg.dingtalk.api.core.response.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.dto.message.MessageDTO;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.config.TenantContext;
@ -17,6 +17,7 @@ import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.system.entity.SysThirdAccount;
import org.jeecg.modules.system.entity.SysThirdAppConfig;
import org.jeecg.modules.system.service.ISysThirdAccountService;
@ -27,6 +28,7 @@ import org.jeecg.modules.system.vo.thirdapp.JwSysUserDepartVo;
import org.jeecg.modules.system.vo.thirdapp.JwUserDepartVo;
import org.jeecg.modules.system.vo.thirdapp.SyncInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
@ -483,7 +485,7 @@ public class ThirdAppController {
*/
@GetMapping("/getThirdAccountByUserId")
public Result<List<SysThirdAccount>> getThirdAccountByUserId(@RequestParam(name="thirdType") String thirdType){
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
LambdaQueryWrapper<SysThirdAccount> query = new LambdaQueryWrapper<>();
//根据id查询
query.eq(SysThirdAccount::getSysUserId,sysUser.getId());
@ -514,7 +516,7 @@ public class ThirdAppController {
*/
@DeleteMapping("/deleteThirdAccount")
public Result<String> deleteThirdAccountById(@RequestBody SysThirdAccount sysThirdAccount){
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
if(!sysUser.getId().equals(sysThirdAccount.getSysUserId())){
return Result.error("无权修改他人信息");
}

View File

@ -1,5 +1,6 @@
package org.jeecg.modules.system.entity;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
@ -7,9 +8,10 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.config.security.utils.SecureUtil;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.core.context.SecurityContextHolder;
import java.io.Serializable;
import java.util.Date;
@ -93,7 +95,7 @@ public class SysDataLog implements Serializable {
*/
public void autoSetCreateName() {
try {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
this.setCreateName(sysUser.getRealname());
} catch (Exception e) {
log.warn("SecurityUtils.getSubject() 获取用户信息异常:" + e.getMessage());

View File

@ -61,7 +61,7 @@ public class SysUser implements Serializable {
/**
* md5密码盐
*/
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@JsonProperty(access = JsonProperty.Access.READ_WRITE)
private String salt;
/**

View File

@ -1,16 +1,17 @@
package org.jeecg.modules.system.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.DateRangeUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.system.entity.SysAnnouncement;
import org.jeecg.modules.system.entity.SysAnnouncementSend;
import org.jeecg.modules.system.mapper.SysAnnouncementMapper;
@ -19,6 +20,7 @@ import org.jeecg.modules.system.mapper.SysUserMapper;
import org.jeecg.modules.system.service.ISysAnnouncementSendService;
import org.jeecg.modules.system.service.ISysAnnouncementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@ -155,7 +157,7 @@ public class SysAnnouncementServiceImpl extends ServiceImpl<SysAnnouncementMappe
@Override
public void completeAnnouncementSendInfo() {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
String userId = sysUser.getId();
List<String> announcementIds = this.getNotSendedAnnouncementlist(userId);
List<SysAnnouncementSend> sysAnnouncementSendList = new ArrayList<>();
@ -205,7 +207,7 @@ public class SysAnnouncementServiceImpl extends ServiceImpl<SysAnnouncementMappe
// completeAnnouncementSendInfo();
// });
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
log.info(" 获取登录人 LoginUser id: {}", sysUser.getId());
Page<SysAnnouncement> page = new Page<SysAnnouncement>(pageNo,pageSize);
List<SysAnnouncement> list = baseMapper.queryAllMessageList(page, sysUser.getId(), fromUser, starFlag, beginDate, endDate);
@ -214,13 +216,13 @@ public class SysAnnouncementServiceImpl extends ServiceImpl<SysAnnouncementMappe
@Override
public void updateReaded(List<String> annoceIdList) {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
sysAnnouncementSendMapper.updateReaded(sysUser.getId(), annoceIdList);
}
@Override
public void clearAllUnReadMessage() {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
sysAnnouncementSendMapper.clearAllUnReadMessage(sysUser.getId());
}

View File

@ -17,10 +17,10 @@ import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.dto.DataLogDTO;
import org.jeecg.common.api.dto.OnlineAuthDTO;
import org.jeecg.common.api.dto.message.*;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.UrlMatchEnum;
import org.jeecg.common.constant.*;
import org.jeecg.common.constant.enums.EmailTemplateEnum;
@ -39,6 +39,7 @@ import org.jeecg.common.util.dynamic.db.FreemarkerParseFactory;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.firewall.SqlInjection.IDictTableWhiteListHandler;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.message.entity.SysMessageTemplate;
import org.jeecg.modules.message.handle.impl.DdSendMsgHandle;
import org.jeecg.modules.message.handle.impl.EmailSendMsgHandle;
@ -54,6 +55,7 @@ import org.jeecg.modules.system.vo.lowapp.SysDictVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.util.AntPathMatcher;
@ -169,6 +171,19 @@ public class SysBaseApiImpl implements ISysBaseAPI {
}
@Override
public LoginUser getUserByPhone(String phone) {
if (oConvertUtils.isEmpty(phone)) {
return null;
}
LoginUser loginUser = new LoginUser();
SysUser sysUser = sysUserService.getUserByPhone(phone);
BeanUtils.copyProperties(sysUser, loginUser);
return loginUser;
}
@Override
public String translateDictFromTable(String table, String text, String code, String key) {
return sysDictService.queryTableDictTextByKey(table, text, code, key);
@ -632,7 +647,7 @@ public class SysBaseApiImpl implements ISysBaseAPI {
public void updateSysAnnounReadFlag(String busType, String busId) {
SysAnnouncement announcement = sysAnnouncementMapper.selectOne(new QueryWrapper<SysAnnouncement>().eq("bus_type",busType).eq("bus_id",busId));
if(announcement != null){
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
String userId = sysUser.getId();
LambdaUpdateWrapper<SysAnnouncementSend> updateWrapper = new UpdateWrapper().lambda();
updateWrapper.set(SysAnnouncementSend::getReadFlag, CommonConstant.HAS_READ_FLAG);
@ -1551,6 +1566,27 @@ public class SysBaseApiImpl implements ISysBaseAPI {
}
//update-end---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
@Override
public Map<String, List<DictModel>> queryAllDictItems() {
return sysDictService.queryAllDictItems();
}
@Override
public List<SysDepartModel> queryUserDeparts(String userId) {
List<SysDepartModel> list = new ArrayList<>();
for (SysDepart sysDepartService: sysDepartService.queryUserDeparts(userId)) {
SysDepartModel model = new SysDepartModel();
BeanUtils.copyProperties(sysDepartService, model);
list.add(model);
}
return list;
}
@Override
public void updateUserDepart(String username, String orgCode, Integer loginTenantId) {
sysUserService.updateUserDepart(username, orgCode,null);
}
//-------------------------------------流程节点发送模板消息-----------------------------------------------
@Autowired
private QywxSendMsgHandle qywxSendMsgHandle;
@ -1819,4 +1855,11 @@ public class SysBaseApiImpl implements ISysBaseAPI {
}
}
@Override
public JSONObject setLoginTenant(String username) {
JSONObject obj = new JSONObject(new LinkedHashMap<>());
SysUser sysUser = sysUserService.getUserByName(username);
sysUserService.setLoginTenant(sysUser, obj, username, null);
return obj;
}
}

View File

@ -2,6 +2,7 @@ package org.jeecg.modules.system.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -12,7 +13,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.netty.util.internal.StringUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.FillRuleConstant;
@ -23,6 +23,7 @@ import org.jeecg.common.util.ImportExcelUtil;
import org.jeecg.common.util.YouBianCodeUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.system.entity.*;
import org.jeecg.modules.system.mapper.*;
import org.jeecg.modules.system.model.DepartIdModel;
@ -32,6 +33,8 @@ import org.jeecg.modules.system.util.FindsDepartsChildrenUtil;
import org.jeecg.modules.system.vo.SysDepartExportVo;
import org.jeecg.modules.system.vo.lowapp.ExportDepartVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -857,7 +860,7 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
*/
@Override
public List<SysDepart> getMyDepartList() {
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();
String userId = user.getId();
//字典code集合
List<String> list = new ArrayList<>();

View File

@ -1,12 +1,13 @@
package org.jeecg.modules.system.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.constant.TenantConstant;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.aop.TenantLog;
import org.jeecg.modules.system.entity.SysPackPermission;
import org.jeecg.modules.system.entity.SysTenant;
@ -19,6 +20,7 @@ import org.jeecg.modules.system.mapper.SysTenantPackUserMapper;
import org.jeecg.modules.system.service.ISysTenantPackService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -146,7 +148,7 @@ public class SysTenantPackServiceImpl extends ServiceImpl<SysTenantPackMapper, S
packId = sysTenantPackSuperAdmin.getId();
}
//step.1.2 补充人员与套餐包的关系数据
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
SysTenantPackUser packUser = new SysTenantPackUser(tenantId, packId, sysUser.getId());
packUser.setRealname(sysUser.getRealname());
packUser.setPackName(superAdminPack.getPackName());

View File

@ -1,6 +1,7 @@
package org.jeecg.modules.system.service.impl;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -24,6 +25,7 @@ import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.constant.enums.SysAnnmentTypeEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.aop.TenantLog;
import org.jeecg.modules.system.entity.*;
import org.jeecg.modules.system.mapper.*;
@ -31,11 +33,9 @@ import org.jeecg.modules.system.service.ISysTenantPackService;
import org.jeecg.modules.system.service.ISysTenantService;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.system.vo.tenant.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.util.*;
@ -177,7 +177,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
this.save(sysTenant);
//update-begin---author:wangshuai ---date:20230710 for【QQYUN-5723】1、把当前创建人加入到租户关系里面------------
//当前登录人的id
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser loginUser = SecureUtil.currentUser();
this.saveTenantRelation(sysTenant.getId(),loginUser.getId());
//update-end---author:wangshuai ---date:20230710 for【QQYUN-5723】1、把当前创建人加入到租户关系里面------------
}
@ -378,7 +378,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
@Override
public Result<String> invitationUser(String phone, String departId) {
Result<String> result = new Result<>();
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
//1、查询用户信息,判断用户是否存在
SysUser userByPhone = userService.getUserByPhone(phone);
@ -442,7 +442,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
}
TenantDepartAuthInfo info = new TenantDepartAuthInfo();
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
String userId = sysUser.getId();
boolean superAdmin = false;
// 查询pack表
@ -632,7 +632,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
// 发消息
SysUser user = userService.getById(sysTenantPackUser.getUserId());
SysTenant sysTenant = this.baseMapper.querySysTenant(sysTenantPackUser.getTenantId());
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser loginUser = SecureUtil.currentUser();
MessageDTO messageDTO = new MessageDTO();
messageDTO.setToAll(false);
messageDTO.setToUser(user.getUsername());
@ -804,7 +804,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
@Override
public Long getApplySuperAdminCount() {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
int tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
return baseMapper.getApplySuperAdminCount(sysUser.getId(),tenantId);
}

View File

@ -1,5 +1,6 @@
package org.jeecg.modules.system.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeecg.dingtalk.api.base.JdtBaseAPI;
@ -7,7 +8,6 @@ import com.jeecg.dingtalk.api.core.response.Response;
import com.jeecg.dingtalk.api.core.vo.AccessToken;
import com.jeecg.dingtalk.api.user.JdtUserAPI;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.LoginUser;
@ -15,6 +15,7 @@ import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.UUIDGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.system.entity.SysRole;
import org.jeecg.modules.system.entity.SysThirdAccount;
import org.jeecg.modules.system.entity.SysUser;
@ -27,6 +28,7 @@ import org.jeecg.modules.system.model.ThirdLoginModel;
import org.jeecg.modules.system.service.ISysThirdAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.util.Date;
@ -190,7 +192,7 @@ public class SysThirdAccountServiceImpl extends ServiceImpl<SysThirdAccountMappe
String thirdUserUuid = sysThirdAccount.getThirdUserUuid();
String thirdType = sysThirdAccount.getThirdType();
//获取当前登录用户
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
//当前第三方用户已被其他用户所绑定
SysThirdAccount oneByThirdUserId = this.getOneByUuidAndThirdType(thirdUserUuid, thirdType,CommonConstant.TENANT_ID_DEFAULT_VALUE, null);
if(null != oneByThirdUserId){

View File

@ -1,17 +1,18 @@
package org.jeecg.modules.system.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.entity.SysUserDepart;
@ -25,6 +26,7 @@ import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.system.vo.SysUserDepVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.util.*;
@ -225,7 +227,7 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
IPage<SysUser> pageList = null;
// 部门ID不存在 直接查询用户表即可
Page<SysUser> page = new Page<>(pageNo, pageSize);
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
if(oConvertUtils.isEmpty(departId)){
LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>();
query.eq(SysUser::getStatus,Integer.parseInt(CommonConstant.STATUS_1));
@ -263,7 +265,7 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
IPage<SysUser> pageList = null;
// 部门ID不存在 直接查询用户表即可
Page<SysUser> page = new Page<>(pageNo, pageSize);
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
List<String> userIdList = new ArrayList<>();
if(oConvertUtils.isNotEmpty(excludeUserIdList)){

View File

@ -2,6 +2,7 @@ package org.jeecg.modules.system.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
@ -15,7 +16,6 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.dto.message.MessageDTO;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.config.TenantContext;
@ -33,6 +33,7 @@ import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.system.vo.SysUserCacheInfo;
import org.jeecg.common.util.*;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.message.handle.impl.SystemSendMsgHandle;
import org.jeecg.modules.system.entity.*;
@ -60,6 +61,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
@ -1573,7 +1575,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "用户列表");
mv.addObject(NormalExcelConstants.CLASS, AppExportUserVo.class);
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser user = SecureUtil.currentUser();;
ExportParams exportParams = new ExportParams("导入规则:\n" +
"1、存在用户编号时数据会根据用户编号进行匹配匹配成功后只会更新职位和工号;\n" +
"2、不存在用户编号时支持手机号、邮箱、姓名、部们、职位、工号导入,其中手机号必填;\n" +
@ -1881,7 +1883,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
userTenantMapper.insert(userTenant);
//update-begin---author:wangshuai ---date:20230710 for【QQYUN-5731】导入用户时没有提醒------------
//发送系统消息通知
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
MessageDTO messageDTO = new MessageDTO();
String title = sysUser.getRealname() + " 邀请您加入 " + tenantName + "";
messageDTO.setTitle(title);

View File

@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;

View File

@ -35,7 +35,7 @@ import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.security.access.prepost.PreAuthorize;
<#assign bpm_flag=false>
<#list originalColumns as po>
<#if po.fieldDbName=='bpm_status'>
@ -87,7 +87,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
*/
@AutoLog(value = "${tableVo.ftlDescription}-添加")
@Operation(summary="${tableVo.ftlDescription}-添加")
@RequiresPermissions("${entityPackage}:${tableName}:add")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:add')")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody ${entityName} ${entityName?uncap_first}) {
<#if bpm_flag>
@ -105,7 +105,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
*/
@AutoLog(value = "${tableVo.ftlDescription}-编辑")
@Operation(summary="${tableVo.ftlDescription}-编辑")
@RequiresPermissions("${entityPackage}:${tableName}:edit")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:edit')")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody ${entityName} ${entityName?uncap_first}) {
${entityName?uncap_first}Service.updateById(${entityName?uncap_first});
@ -120,7 +120,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
*/
@AutoLog(value = "${tableVo.ftlDescription}-通过id删除")
@Operation(summary="${tableVo.ftlDescription}-通过id删除")
@RequiresPermissions("${entityPackage}:${tableName}:delete")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:delete')")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
${entityName?uncap_first}Service.removeById(id);
@ -135,7 +135,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
*/
@AutoLog(value = "${tableVo.ftlDescription}-批量删除")
@Operation(summary="${tableVo.ftlDescription}-批量删除")
@RequiresPermissions("${entityPackage}:${tableName}:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:deleteBatch')")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.${entityName?uncap_first}Service.removeByIds(Arrays.asList(ids.split(",")));
@ -165,7 +165,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
* @param request
* @param ${entityName?uncap_first}
*/
@RequiresPermissions("${entityPackage}:${tableName}:exportXls")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:exportXls')")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, ${entityName} ${entityName?uncap_first}) {
return super.exportXls(request, ${entityName?uncap_first}, ${entityName}.class, "${tableVo.ftlDescription}");
@ -178,7 +178,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
* @param response
* @return
*/
@RequiresPermissions("${entityPackage}:${tableName}:importExcel")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:importExcel')")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, ${entityName}.class);

View File

@ -18,7 +18,7 @@ import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.vo.LoginUser;
import org.apache.shiro.SecurityUtils;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
@ -45,7 +45,7 @@ import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.security.access.prepost.PreAuthorize;
<#assign bpm_flag=false>
<#list originalColumns as po>
<#if po.fieldDbName=='bpm_status'>
@ -101,7 +101,7 @@ public class ${entityName}Controller {
*/
@AutoLog(value = "${tableVo.ftlDescription}-添加")
@Operation(summary="${tableVo.ftlDescription}-添加")
@RequiresPermissions("${entityPackage}:${tableName}:add")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:add')")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) {
${entityName} ${entityName?uncap_first} = new ${entityName}();
@ -121,7 +121,7 @@ public class ${entityName}Controller {
*/
@AutoLog(value = "${tableVo.ftlDescription}-编辑")
@Operation(summary="${tableVo.ftlDescription}-编辑")
@RequiresPermissions("${entityPackage}:${tableName}:edit")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:edit')")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) {
${entityName} ${entityName?uncap_first} = new ${entityName}();
@ -142,7 +142,7 @@ public class ${entityName}Controller {
*/
@AutoLog(value = "${tableVo.ftlDescription}-通过id删除")
@Operation(summary="${tableVo.ftlDescription}-通过id删除")
@RequiresPermissions("${entityPackage}:${tableName}:delete")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:delete')")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
${entityName?uncap_first}Service.delMain(id);
@ -157,7 +157,7 @@ public class ${entityName}Controller {
*/
@AutoLog(value = "${tableVo.ftlDescription}-批量删除")
@Operation(summary="${tableVo.ftlDescription}-批量删除")
@RequiresPermissions("${entityPackage}:${tableName}:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:deleteBatch')")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.${entityName?uncap_first}Service.delBatchMain(Arrays.asList(ids.split(",")));
@ -204,12 +204,12 @@ public class ${entityName}Controller {
* @param request
* @param ${entityName?uncap_first}
*/
@RequiresPermissions("${entityPackage}:${tableName}:exportXls")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:exportXls')")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, ${entityName} ${entityName?uncap_first}) {
// Step.1 组装查询条件查询数据
QueryWrapper<${entityName}> queryWrapper = QueryGenerator.initQueryWrapper(${entityName?uncap_first}, request.getParameterMap());
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
//配置选中数据查询条件
String selections = request.getParameter("selections");
@ -248,7 +248,7 @@ public class ${entityName}Controller {
* @param response
* @return
*/
@RequiresPermissions("${entityPackage}:${tableName}:importExcel")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:importExcel')")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;

View File

@ -34,7 +34,7 @@ import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -207,7 +207,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
*/
@AutoLog(value = "${tableVo.ftlDescription}-添加")
@Operation(summary="${tableVo.ftlDescription}-添加")
@RequiresPermissions("${entityPackage}:${tableName}:add")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:add')")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody ${entityName} ${entityName?uncap_first}) {
${entityName?uncap_first}Service.add${entityName}(${entityName?uncap_first});
@ -222,7 +222,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
*/
@AutoLog(value = "${tableVo.ftlDescription}-编辑")
@Operation(summary="${tableVo.ftlDescription}-编辑")
@RequiresPermissions("${entityPackage}:${tableName}:edit")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:edit')")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody ${entityName} ${entityName?uncap_first}) {
${entityName?uncap_first}Service.update${entityName}(${entityName?uncap_first});
@ -237,7 +237,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
*/
@AutoLog(value = "${tableVo.ftlDescription}-通过id删除")
@Operation(summary="${tableVo.ftlDescription}-通过id删除")
@RequiresPermissions("${entityPackage}:${tableName}:delete")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:delete')")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
${entityName?uncap_first}Service.delete${entityName}(id);
@ -252,7 +252,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
*/
@AutoLog(value = "${tableVo.ftlDescription}-批量删除")
@Operation(summary="${tableVo.ftlDescription}-批量删除")
@RequiresPermissions("${entityPackage}:${tableName}:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:deleteBatch')")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.${entityName?uncap_first}Service.removeByIds(Arrays.asList(ids.split(",")));
@ -282,7 +282,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
* @param request
* @param ${entityName?uncap_first}
*/
@RequiresPermissions("${entityPackage}:${tableName}:exportXls")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:exportXls')")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, ${entityName} ${entityName?uncap_first}) {
return super.exportXls(request, ${entityName?uncap_first}, ${entityName}.class, "${tableVo.ftlDescription}");
@ -295,7 +295,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
* @param response
* @return
*/
@RequiresPermissions("${entityPackage}:${tableName}:importExcel")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:importExcel')")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, ${entityName}.class);

View File

@ -25,7 +25,7 @@ import ${bussiPackage}.${entityPackage}.service.I${sub.entityName}Service;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.SecurityUtils;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
@ -38,7 +38,7 @@ import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.security.access.prepost.PreAuthorize;
/**
* @Description: ${tableVo.ftlDescription}
@ -91,7 +91,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
*/
@AutoLog(value = "${tableVo.ftlDescription}-添加")
@Operation(summary="${tableVo.ftlDescription}-添加")
@RequiresPermissions("${entityPackage}:${tableName}:add")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:add')")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody ${entityName} ${entityName?uncap_first}) {
${entityName?uncap_first}Service.save(${entityName?uncap_first});
@ -105,7 +105,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
*/
@AutoLog(value = "${tableVo.ftlDescription}-编辑")
@Operation(summary="${tableVo.ftlDescription}-编辑")
@RequiresPermissions("${entityPackage}:${tableName}:edit")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:edit')")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody ${entityName} ${entityName?uncap_first}) {
${entityName?uncap_first}Service.updateById(${entityName?uncap_first});
@ -119,7 +119,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
*/
@AutoLog(value = "${tableVo.ftlDescription}-通过id删除")
@Operation(summary="${tableVo.ftlDescription}-通过id删除")
@RequiresPermissions("${entityPackage}:${tableName}:delete")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:delete')")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
${entityName?uncap_first}Service.delMain(id);
@ -133,7 +133,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
*/
@AutoLog(value = "${tableVo.ftlDescription}-批量删除")
@Operation(summary="${tableVo.ftlDescription}-批量删除")
@RequiresPermissions("${entityPackage}:${tableName}:deleteBatch")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:deleteBatch')")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.${entityName?uncap_first}Service.delBatchMain(Arrays.asList(ids.split(",")));
@ -144,7 +144,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
* 导出
* @return
*/
@RequiresPermissions("${entityPackage}:${tableName}:exportXls")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:exportXls')")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, ${entityName} ${entityName?uncap_first}) {
return super.exportXls(request, ${entityName?uncap_first}, ${entityName}.class, "${tableVo.ftlDescription}");
@ -154,7 +154,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
* 导入
* @return
*/
@RequiresPermissions("${entityPackage}:${tableName}:importExcel")
@PreAuthorize("@jps.requiresPermissions('${entityPackage}:${tableName}:importExcel')")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, ${entityName}.class);
@ -241,7 +241,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
public ModelAndView export${sub.entityName}(HttpServletRequest request, ${sub.entityName} ${sub.entityName?uncap_first}) {
// Step.1 组装查询条件
QueryWrapper<${sub.entityName}> queryWrapper = QueryGenerator.initQueryWrapper(${sub.entityName?uncap_first}, request.getParameterMap());
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
LoginUser sysUser = SecureUtil.currentUser();
// Step.2 获取导出数据
List<${sub.entityName}> pageList = ${sub.entityName?uncap_first}Service.list(queryWrapper);

Some files were not shown because too many files have changed in this diff Show More