From 9245a0641d66c1696be0680cf72260838396ccfc Mon Sep 17 00:00:00 2001 From: andy <1042025947@qq.com> Date: Wed, 16 Apr 2025 16:05:30 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hd/common/web/util}/SpringUtil.java | 2 +- ... => PermissionCloudMybatisPlusConfig.java} | 4 +- .../MqttMessageRequestExchangeProcessor.java | 3 +- .../hd/cloud/utils/RedisCloudUtils.java | 1 + resource-server/pom.xml | 14 ++ .../PermissionResourceMybatisPlusConfig.java | 31 +++ .../hd/resource/handler/DataScopeHandler.java | 115 +++++++++++ .../hd/resource/utils/RedisResourceUtils.java | 179 ++++++++++++++++++ .../evotech/hd/resource/utils/TokenUtil.java | 56 ++++++ wechat-server/pom.xml | 12 +- .../PermissionWechatMybatisPlusConfig.java | 30 +++ .../hd/wechat/handler/DataScopeHandler.java | 115 +++++++++++ .../utils/permission/RedisWechatUtils.java | 179 ++++++++++++++++++ .../hd/wechat/utils/permission/TokenUtil.java | 56 ++++++ 14 files changed, 790 insertions(+), 7 deletions(-) rename {cloud-manage-server/src/main/java/com/evotech/hd/cloud/utils => base-commons/common-web/src/main/java/com/evotech/hd/common/web/util}/SpringUtil.java (98%) rename cloud-manage-server/src/main/java/com/evotech/hd/cloud/config/{NewMybatisPlusConfig.java => PermissionCloudMybatisPlusConfig.java} (91%) create mode 100644 resource-server/src/main/java/com/evotech/hd/resource/config/permission/PermissionResourceMybatisPlusConfig.java create mode 100644 resource-server/src/main/java/com/evotech/hd/resource/handler/DataScopeHandler.java create mode 100644 resource-server/src/main/java/com/evotech/hd/resource/utils/RedisResourceUtils.java create mode 100644 resource-server/src/main/java/com/evotech/hd/resource/utils/TokenUtil.java create mode 100644 wechat-server/src/main/java/com/evotech/hd/wechat/config/PermissionWechatMybatisPlusConfig.java create mode 100644 wechat-server/src/main/java/com/evotech/hd/wechat/handler/DataScopeHandler.java create mode 100644 wechat-server/src/main/java/com/evotech/hd/wechat/utils/permission/RedisWechatUtils.java create mode 100644 wechat-server/src/main/java/com/evotech/hd/wechat/utils/permission/TokenUtil.java diff --git a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/utils/SpringUtil.java b/base-commons/common-web/src/main/java/com/evotech/hd/common/web/util/SpringUtil.java similarity index 98% rename from cloud-manage-server/src/main/java/com/evotech/hd/cloud/utils/SpringUtil.java rename to base-commons/common-web/src/main/java/com/evotech/hd/common/web/util/SpringUtil.java index 00814a2..7086f1f 100644 --- a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/utils/SpringUtil.java +++ b/base-commons/common-web/src/main/java/com/evotech/hd/common/web/util/SpringUtil.java @@ -1,4 +1,4 @@ -package com.evotech.hd.cloud.utils; +package com.evotech.hd.common.web.util; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; diff --git a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/config/NewMybatisPlusConfig.java b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/config/PermissionCloudMybatisPlusConfig.java similarity index 91% rename from cloud-manage-server/src/main/java/com/evotech/hd/cloud/config/NewMybatisPlusConfig.java rename to cloud-manage-server/src/main/java/com/evotech/hd/cloud/config/PermissionCloudMybatisPlusConfig.java index 57e3f3d..d96942d 100644 --- a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/config/NewMybatisPlusConfig.java +++ b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/config/PermissionCloudMybatisPlusConfig.java @@ -17,9 +17,9 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; */ @EnableTransactionManagement(proxyTargetClass = true) @Configuration -public class NewMybatisPlusConfig { +public class PermissionCloudMybatisPlusConfig { - @Bean("newMybatisPlusInterceptor") + @Bean("permissionCloudMybatisPlusInterceptor") public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); diff --git a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/mqtt/message/processor/MqttMessageRequestExchangeProcessor.java b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/mqtt/message/processor/MqttMessageRequestExchangeProcessor.java index b5d44e2..4b8cd5c 100644 --- a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/mqtt/message/processor/MqttMessageRequestExchangeProcessor.java +++ b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/mqtt/message/processor/MqttMessageRequestExchangeProcessor.java @@ -10,9 +10,8 @@ import com.evotech.hd.cloud.mqtt.enums.RequestFunctionTypesEnum; import com.evotech.hd.cloud.mqtt.message.MessageTopic; import com.evotech.hd.cloud.mqtt.message.MqttMessageHeader; import com.evotech.hd.cloud.mqtt.message.dto.newer.req.MqttResponse; -import com.evotech.hd.cloud.mqtt.message.dto.newer.req.order.CancelOrderReq; import com.evotech.hd.cloud.mqtt.message.handle.MessageUtilService; -import com.evotech.hd.cloud.utils.SpringUtil; +import com.evotech.hd.common.web.util.SpringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/utils/RedisCloudUtils.java b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/utils/RedisCloudUtils.java index c996c82..f461029 100644 --- a/cloud-manage-server/src/main/java/com/evotech/hd/cloud/utils/RedisCloudUtils.java +++ b/cloud-manage-server/src/main/java/com/evotech/hd/cloud/utils/RedisCloudUtils.java @@ -4,6 +4,7 @@ import com.evotech.hd.common.core.constant.HDConstant; import com.evotech.hd.common.core.entity.resource.auth.AuthUser; import com.evotech.hd.common.redis.utils.RedisUtil; import com.evotech.hd.common.web.util.RequestContextUtil; +import com.evotech.hd.common.web.util.SpringUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; diff --git a/resource-server/pom.xml b/resource-server/pom.xml index b9ac9a8..aaee8fe 100644 --- a/resource-server/pom.xml +++ b/resource-server/pom.xml @@ -66,6 +66,20 @@ io.minio minio + + com.evotech.hd + common-redis + 1.0.0-SNAPSHOT + compile + + + cn.hutool + hutool-jwt + + + org.springframework.security + spring-security-oauth2-jose + diff --git a/resource-server/src/main/java/com/evotech/hd/resource/config/permission/PermissionResourceMybatisPlusConfig.java b/resource-server/src/main/java/com/evotech/hd/resource/config/permission/PermissionResourceMybatisPlusConfig.java new file mode 100644 index 0000000..595444c --- /dev/null +++ b/resource-server/src/main/java/com/evotech/hd/resource/config/permission/PermissionResourceMybatisPlusConfig.java @@ -0,0 +1,31 @@ +package com.evotech.hd.resource.config.permission; + +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor; +import com.evotech.hd.resource.handler.DataScopeHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @desc: + * @ClassName:MybatisPlusConfig + * @date: 2025年04月14日 16:14 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@EnableTransactionManagement(proxyTargetClass = true) +@Configuration +public class PermissionResourceMybatisPlusConfig { + + @Bean("permissionResourceMybatisPlusInterceptor") + public MybatisPlusInterceptor mybatisPlusInterceptor() { + + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 数据权限插件 + interceptor.addInnerInterceptor(new DataPermissionInterceptor(new DataScopeHandler())); + return interceptor; + } + +} diff --git a/resource-server/src/main/java/com/evotech/hd/resource/handler/DataScopeHandler.java b/resource-server/src/main/java/com/evotech/hd/resource/handler/DataScopeHandler.java new file mode 100644 index 0000000..b52f9ce --- /dev/null +++ b/resource-server/src/main/java/com/evotech/hd/resource/handler/DataScopeHandler.java @@ -0,0 +1,115 @@ +package com.evotech.hd.resource.handler; + +import com.alibaba.nacos.common.utils.CollectionUtils; +import com.alibaba.nacos.common.utils.StringUtils; +import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler; +import com.evotech.hd.common.core.permission.DataScope; +import com.evotech.hd.common.core.permission.DataScopes; +import com.evotech.hd.resource.utils.RedisResourceUtils; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.Parenthesis; +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.InExpression; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import org.apache.commons.lang3.ObjectUtils; + +import java.util.Arrays; +import java.util.stream.Collectors; + +/** + * @desc: + * @ClassName:DataScopeHandler + * @date: 2025年04月14日 14:54 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ + +public class DataScopeHandler implements MultiDataPermissionHandler { + + /** + * 获取数据权限 SQL 片段。 + *

旧的 {@link MultiDataPermissionHandler#getSqlSegment(Expression, String)} 方法第一个参数包含所有的 where 条件信息,如果 return 了 null 会覆盖原有的 where 数据,

+ *

新版的 {@link MultiDataPermissionHandler#getSqlSegment(Table, Expression, String)} 方法不能覆盖原有的 where 数据,如果 return 了 null 则表示不追加任何 where 条件

+ * + * @param table 所执行的数据库表信息,可以通过此参数获取表名和表别名 + * @param where 原有的 where 条件信息 + * @param mappedStatementId Mybatis MappedStatement Id 根据该参数可以判断具体执行方法 + * @return JSqlParser 条件表达式,返回的条件表达式会拼接在原有的表达式后面(不会覆盖原有的表达式) + */ + + @Override + public Expression getSqlSegment(Table table, Expression where, String mappedStatementId) { + try { + if(table != null && CollectionUtils.isNotEmpty(table.getNameParts()) && !"1".equals(RedisResourceUtils.getRoleType())){ + String roleCode = RedisResourceUtils.getRoleCode(); + Class mapperClazz = Class.forName(mappedStatementId.substring(0, mappedStatementId.lastIndexOf("."))); + //优先检查是不是单角色权限 + DataScope dataScope = mapperClazz.getAnnotation(DataScope.class); + if (ObjectUtils.isNotEmpty(dataScope) && dataScope.enabled()) { + if(dataScope.permissionObject().equals(roleCode)){ + return buildDataScopeByAnnotation(dataScope); + } + } + //如果不是, 检查多角色权限 + DataScopes dataScopesList = mapperClazz.getAnnotation(DataScopes.class); + if (ObjectUtils.isNotEmpty(dataScopesList)) { + for (DataScope dataScopes :dataScopesList.value()){ + if(dataScopes.enabled()){ + if(dataScopes.permissionObject().equals(roleCode)){ + return buildDataScopeByAnnotation(dataScopes); + } + } + } + } + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return null; + } + + + + /** + * DataScope注解方式,拼装数据权限 + * + * @param dataScope + * @return + */ + private Expression buildDataScopeByAnnotation(DataScope dataScope) { + Expression expression = buildDataScopeExpression(dataScope, RedisResourceUtils.getPermissionValue(dataScope.permissionScopeRedisKey())); + return expression == null ? null : new Parenthesis(expression); + } + + + private Expression buildDataScopeExpression(DataScope dataScope, String value) { + if(!"null".equals(value)){ + ExpressionList expressionList = new ExpressionList(Arrays.asList(value.split(",")).stream().map(StringValue::new).collect(Collectors.toList())); + // 设置左边的字段表达式,右边设置值。 + InExpression operatorInExpression = new InExpression(); + operatorInExpression.setLeftExpression(buildColumn(dataScope.tableAlias(), dataScope.permissionScopeName())); + operatorInExpression.setRightExpression(new Parenthesis(expressionList)); + return operatorInExpression; + + } + return null; + } + + /** + * 构建Column + * + * @param tableAlias 表别名 + * @param columnName 字段名称 + * @return 带表别名字段 + */ + private static Column buildColumn(String tableAlias, String columnName) { + if (StringUtils.isNotEmpty(tableAlias)) { + columnName = tableAlias + "." + columnName; + } + return new Column(columnName); + } + +} diff --git a/resource-server/src/main/java/com/evotech/hd/resource/utils/RedisResourceUtils.java b/resource-server/src/main/java/com/evotech/hd/resource/utils/RedisResourceUtils.java new file mode 100644 index 0000000..7960a80 --- /dev/null +++ b/resource-server/src/main/java/com/evotech/hd/resource/utils/RedisResourceUtils.java @@ -0,0 +1,179 @@ +package com.evotech.hd.resource.utils; + +import com.evotech.hd.common.core.constant.HDConstant; +import com.evotech.hd.common.core.entity.resource.auth.AuthUser; +import com.evotech.hd.common.redis.utils.RedisUtil; +import com.evotech.hd.common.web.util.RequestContextUtil; +import com.evotech.hd.common.web.util.SpringUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +/** + * @desc: + * @ClassName:RedisCloudUtils + * @date: 2025年04月14日 15:24 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ + +@Slf4j +public class RedisResourceUtils { + + public static AuthUser getUser(){ + AuthUser user = (AuthUser)getRedisObjectValue("user"); + return (ObjectUtils.isEmpty(user) ? null : user); + } + + public static String getRoleCode(){ + String roles = getRedisStringValue("rcodes"); + return StringUtils.isEmpty(roles) ? "" : roles; + } + + public static String getPermissionValue(String key){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + key+":"+getUserPkId()); + } + + public static String getStationCode(){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + HDConstant.PermissionConstant.PERMISSION_STATION_CODE+":"+getUserPkId()); + } + public static String getStationId(){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + HDConstant.PermissionConstant.PERMISSION_STATION_ID+":"+getUserPkId()); + } + + public static String getCompanyCode(){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + HDConstant.PermissionConstant.PERMISSION_COMPANY_CODE+":"+getUserPkId()); + } + public static String getCompanyId(){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + HDConstant.PermissionConstant.PERMISSION_COMPANY_ID+":"+getUserPkId()); + } + + public static String getCarCode(){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + HDConstant.PermissionConstant.PERMISSION_CAR_CODE+":"+getUserPkId()); + } + public static String getCarId(){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + HDConstant.PermissionConstant.PERMISSION_CAR_ID+":"+getUserPkId()); + } + + private static Integer getUserPkId(){ + AuthUser user = getUser(); + if(org.apache.commons.lang3.ObjectUtils.isEmpty(user) || user.getPkId() == null){ + return null; + } + return user.getPkId(); + } + + +// public static Integer getCompanyScopeId(){ +// return getUser().getPkId(); +// } + + + /** + * 获取当前登录的角色信息, 0 站端, 1 管理员, 2 运营商, 3 公司, + * @author: andy.shi + * @contact: 17330188597 + * @date: 2025/4/14/周一 14:21 + * @return: * @return: java.lang.String + */ + public static String getRoleType(){ + String roles = getRoleCode(); + if(isAdmin(roles)){ + return "1"; + } + if(isOperator(roles)){ + return "2"; + } + if(isCompany(roles)){ + return "3"; + } + return "0"; + } + + //如果不等于-1 则证明为管理员 + public static Boolean isAdmin(String roles){ + return isAuthority(roles, HDConstant.SYSTEM_MANAGER_ROLE_CODE); + } + + public static Boolean isOperator(String roles){ + return isAuthority(roles,HDConstant.OPERATOR_ROLE_CODE); + } + + public static Boolean isCompany(String roles){ + return isAuthority(roles,HDConstant.COMPANY_ROLE_CODE); + } + + private static Boolean isAuthority(String checkParamRoles, String paramRoleCode){ + if(org.apache.commons.lang3.StringUtils.isNotEmpty(checkParamRoles)){ + return checkParamRoles.lastIndexOf(paramRoleCode) != -1; + } + return getRoleCode().lastIndexOf(paramRoleCode) != -1; + } + + + /*** + * 根据token拼接key, 获取String结果 + * @param key + * @return + */ + private static String getRedisStringValue(String key) { + return String.valueOf(getRedisObjectValue(key)); + } + + /*** + * 根据token拼接key, 获取Object结果 + * @param key + * @return + */ + private static Object getRedisObjectValue(String key) { + String token = RequestContextUtil.getToken(); + if(StringUtils.isEmpty(token)){ + log.error("SpringUtil.getRedisValue========== token is null"); + return null; + } + String jti = null; + try { + jti = TokenUtil.getJti(token); + if(StringUtils.isEmpty(jti)){ + log.error("SpringUtil.getRedisValue========== jtj is null"); + return null; + } + } catch (Exception e) { + log.error("SpringUtil.gegetRedisValuetUser========== jtj is null"); + return null; + } + return getValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + jti + ":"+key); + } + + + /*** + * 根据key获取redis缓存 + * @param key + * @return + */ + private static String getStringValue(String key){ + Object obj = getValue(key); + return ObjectUtils.isEmpty(obj) ? null : String.valueOf(obj); + } + + /*** + * 根据key获取redis缓存 + * @param key + * @return + */ + private static Object getValue(String key){ + RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class); + if(ObjectUtils.isEmpty(redisUtil)){ + log.error("SpringUtil.getRedisValue========== redisUtil is null"); + } + Object obj = redisUtil.get(key); + if(ObjectUtils.isEmpty(obj)){ + log.error("SpringUtil.getRedisValue=={}========== obj is null",key); + return null; + } + log.info("SpringUtil.getRedisValue=={}===={}",key,String.valueOf(obj)); + return obj; + } + +} diff --git a/resource-server/src/main/java/com/evotech/hd/resource/utils/TokenUtil.java b/resource-server/src/main/java/com/evotech/hd/resource/utils/TokenUtil.java new file mode 100644 index 0000000..5f1e8a9 --- /dev/null +++ b/resource-server/src/main/java/com/evotech/hd/resource/utils/TokenUtil.java @@ -0,0 +1,56 @@ +package com.evotech.hd.resource.utils; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.jwt.JWT; +import cn.hutool.jwt.JWTUtil; +import org.springframework.security.oauth2.jwt.JwtClaimNames; + +import java.util.Date; + +/** + * token解析工具类 + */ +public class TokenUtil { + + + public static JWT parseToJwt(String token) { + JWT parseToken = JWTUtil.parseToken(token); + return parseToken; + } + + + /** + * 从token中获取userId + */ + public static String getUserId(String token) { + String uid = parseToJwt(token).getPayloads().getStr("uid"); + return uid; + } + + /** + * 从token中获取rcodes + */ + public static String getRcodes(String token) { + String uid = parseToJwt(token).getPayloads().getStr("rcodes"); + return uid; + } + + + /** + * 从token中获取jti + */ + public static String getJti(String token) { + String jti = parseToJwt(token).getPayloads().getStr(JwtClaimNames.JTI).replaceAll("-", ""); + return jti; + } + + + /** + * 从token中获取过期时间 + */ + public static Date getExp(String token) { + String exp = parseToJwt(token).getPayloads().getStr(JwtClaimNames.EXP).toString(); + return DateUtil.date(Long.valueOf(exp) * 1000); + } + +} diff --git a/wechat-server/pom.xml b/wechat-server/pom.xml index ef476e8..2f72c85 100644 --- a/wechat-server/pom.xml +++ b/wechat-server/pom.xml @@ -80,8 +80,16 @@ core 3.5.3 - - + + org.springframework.security + spring-security-oauth2-jose + + + cn.hutool + hutool-jwt + + + diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/config/PermissionWechatMybatisPlusConfig.java b/wechat-server/src/main/java/com/evotech/hd/wechat/config/PermissionWechatMybatisPlusConfig.java new file mode 100644 index 0000000..cc52e71 --- /dev/null +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/config/PermissionWechatMybatisPlusConfig.java @@ -0,0 +1,30 @@ +package com.evotech.hd.wechat.config; + +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor; +import com.evotech.hd.wechat.handler.DataScopeHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @desc: + * @ClassName:MybatisPlusConfig + * @date: 2025年04月14日 16:14 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@EnableTransactionManagement(proxyTargetClass = true) +@Configuration +public class PermissionWechatMybatisPlusConfig { + + @Bean("permissionWechatMybatisPlusInterceptor") + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 数据权限插件 + interceptor.addInnerInterceptor(new DataPermissionInterceptor(new DataScopeHandler())); + return interceptor; + } + +} diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/handler/DataScopeHandler.java b/wechat-server/src/main/java/com/evotech/hd/wechat/handler/DataScopeHandler.java new file mode 100644 index 0000000..cea9a20 --- /dev/null +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/handler/DataScopeHandler.java @@ -0,0 +1,115 @@ +package com.evotech.hd.wechat.handler; + +import com.alibaba.nacos.common.utils.CollectionUtils; +import com.alibaba.nacos.common.utils.StringUtils; +import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler; +import com.evotech.hd.common.core.permission.DataScope; +import com.evotech.hd.common.core.permission.DataScopes; +import com.evotech.hd.wechat.utils.permission.RedisWechatUtils; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.Parenthesis; +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.InExpression; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import org.apache.commons.lang3.ObjectUtils; + +import java.util.Arrays; +import java.util.stream.Collectors; + +/** + * @desc: + * @ClassName:DataScopeHandler + * @date: 2025年04月14日 14:54 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ + +public class DataScopeHandler implements MultiDataPermissionHandler { + + /** + * 获取数据权限 SQL 片段。 + *

旧的 {@link MultiDataPermissionHandler#getSqlSegment(Expression, String)} 方法第一个参数包含所有的 where 条件信息,如果 return 了 null 会覆盖原有的 where 数据,

+ *

新版的 {@link MultiDataPermissionHandler#getSqlSegment(Table, Expression, String)} 方法不能覆盖原有的 where 数据,如果 return 了 null 则表示不追加任何 where 条件

+ * + * @param table 所执行的数据库表信息,可以通过此参数获取表名和表别名 + * @param where 原有的 where 条件信息 + * @param mappedStatementId Mybatis MappedStatement Id 根据该参数可以判断具体执行方法 + * @return JSqlParser 条件表达式,返回的条件表达式会拼接在原有的表达式后面(不会覆盖原有的表达式) + */ + + @Override + public Expression getSqlSegment(Table table, Expression where, String mappedStatementId) { + try { + if(table != null && CollectionUtils.isNotEmpty(table.getNameParts()) && !"1".equals(RedisWechatUtils.getRoleType())){ + String roleCode = RedisWechatUtils.getRoleCode(); + Class mapperClazz = Class.forName(mappedStatementId.substring(0, mappedStatementId.lastIndexOf("."))); + //优先检查是不是单角色权限 + DataScope dataScope = mapperClazz.getAnnotation(DataScope.class); + if (ObjectUtils.isNotEmpty(dataScope) && dataScope.enabled()) { + if(dataScope.permissionObject().equals(roleCode)){ + return buildDataScopeByAnnotation(dataScope); + } + } + //如果不是, 检查多角色权限 + DataScopes dataScopesList = mapperClazz.getAnnotation(DataScopes.class); + if (ObjectUtils.isNotEmpty(dataScopesList)) { + for (DataScope dataScopes :dataScopesList.value()){ + if(dataScopes.enabled()){ + if(dataScopes.permissionObject().equals(roleCode)){ + return buildDataScopeByAnnotation(dataScopes); + } + } + } + } + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return null; + } + + + + /** + * DataScope注解方式,拼装数据权限 + * + * @param dataScope + * @return + */ + private Expression buildDataScopeByAnnotation(DataScope dataScope) { + Expression expression = buildDataScopeExpression(dataScope, RedisWechatUtils.getPermissionValue(dataScope.permissionScopeRedisKey())); + return expression == null ? null : new Parenthesis(expression); + } + + + private Expression buildDataScopeExpression(DataScope dataScope, String value) { + if(!"null".equals(value)){ + ExpressionList expressionList = new ExpressionList(Arrays.asList(value.split(",")).stream().map(StringValue::new).collect(Collectors.toList())); + // 设置左边的字段表达式,右边设置值。 + InExpression operatorInExpression = new InExpression(); + operatorInExpression.setLeftExpression(buildColumn(dataScope.tableAlias(), dataScope.permissionScopeName())); + operatorInExpression.setRightExpression(new Parenthesis(expressionList)); + return operatorInExpression; + + } + return null; + } + + /** + * 构建Column + * + * @param tableAlias 表别名 + * @param columnName 字段名称 + * @return 带表别名字段 + */ + private static Column buildColumn(String tableAlias, String columnName) { + if (StringUtils.isNotEmpty(tableAlias)) { + columnName = tableAlias + "." + columnName; + } + return new Column(columnName); + } + +} diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/utils/permission/RedisWechatUtils.java b/wechat-server/src/main/java/com/evotech/hd/wechat/utils/permission/RedisWechatUtils.java new file mode 100644 index 0000000..2b477f0 --- /dev/null +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/utils/permission/RedisWechatUtils.java @@ -0,0 +1,179 @@ +package com.evotech.hd.wechat.utils.permission; + +import com.evotech.hd.common.core.constant.HDConstant; +import com.evotech.hd.common.core.entity.resource.auth.AuthUser; +import com.evotech.hd.common.redis.utils.RedisUtil; +import com.evotech.hd.common.web.util.RequestContextUtil; +import com.evotech.hd.common.web.util.SpringUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +/** + * @desc: + * @ClassName:RedisCloudUtils + * @date: 2025年04月14日 15:24 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ + +@Slf4j +public class RedisWechatUtils { + + public static AuthUser getUser(){ + AuthUser user = (AuthUser)getRedisObjectValue("user"); + return (ObjectUtils.isEmpty(user) ? null : user); + } + + public static String getRoleCode(){ + String roles = getRedisStringValue("rcodes"); + return StringUtils.isEmpty(roles) ? "" : roles; + } + + public static String getPermissionValue(String key){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + key+":"+getUserPkId()); + } + + public static String getStationCode(){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + HDConstant.PermissionConstant.PERMISSION_STATION_CODE+":"+getUserPkId()); + } + public static String getStationId(){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + HDConstant.PermissionConstant.PERMISSION_STATION_ID+":"+getUserPkId()); + } + + public static String getCompanyCode(){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + HDConstant.PermissionConstant.PERMISSION_COMPANY_CODE+":"+getUserPkId()); + } + public static String getCompanyId(){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + HDConstant.PermissionConstant.PERMISSION_COMPANY_ID+":"+getUserPkId()); + } + + public static String getCarCode(){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + HDConstant.PermissionConstant.PERMISSION_CAR_CODE+":"+getUserPkId()); + } + public static String getCarId(){ + return getStringValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + HDConstant.PermissionConstant.PERMISSION_CAR_ID+":"+getUserPkId()); + } + + private static Integer getUserPkId(){ + AuthUser user = getUser(); + if(org.apache.commons.lang3.ObjectUtils.isEmpty(user) || user.getPkId() == null){ + return null; + } + return user.getPkId(); + } + + +// public static Integer getCompanyScopeId(){ +// return getUser().getPkId(); +// } + + + /** + * 获取当前登录的角色信息, 0 站端, 1 管理员, 2 运营商, 3 公司, + * @author: andy.shi + * @contact: 17330188597 + * @date: 2025/4/14/周一 14:21 + * @return: * @return: java.lang.String + */ + public static String getRoleType(){ + String roles = getRoleCode(); + if(isAdmin(roles)){ + return "1"; + } + if(isOperator(roles)){ + return "2"; + } + if(isCompany(roles)){ + return "3"; + } + return "0"; + } + + //如果不等于-1 则证明为管理员 + public static Boolean isAdmin(String roles){ + return isAuthority(roles, HDConstant.SYSTEM_MANAGER_ROLE_CODE); + } + + public static Boolean isOperator(String roles){ + return isAuthority(roles,HDConstant.OPERATOR_ROLE_CODE); + } + + public static Boolean isCompany(String roles){ + return isAuthority(roles,HDConstant.COMPANY_ROLE_CODE); + } + + private static Boolean isAuthority(String checkParamRoles, String paramRoleCode){ + if(org.apache.commons.lang3.StringUtils.isNotEmpty(checkParamRoles)){ + return checkParamRoles.lastIndexOf(paramRoleCode) != -1; + } + return getRoleCode().lastIndexOf(paramRoleCode) != -1; + } + + + /*** + * 根据token拼接key, 获取String结果 + * @param key + * @return + */ + private static String getRedisStringValue(String key) { + return String.valueOf(getRedisObjectValue(key)); + } + + /*** + * 根据token拼接key, 获取Object结果 + * @param key + * @return + */ + private static Object getRedisObjectValue(String key) { + String token = RequestContextUtil.getToken(); + if(StringUtils.isEmpty(token)){ + log.error("SpringUtil.getRedisValue========== token is null"); + return null; + } + String jti = null; + try { + jti = TokenUtil.getJti(token); + if(StringUtils.isEmpty(jti)){ + log.error("SpringUtil.getRedisValue========== jtj is null"); + return null; + } + } catch (Exception e) { + log.error("SpringUtil.gegetRedisValuetUser========== jtj is null"); + return null; + } + return getValue(HDConstant.LOGIN_CACHE_KEY_PREFIX + jti + ":"+key); + } + + + /*** + * 根据key获取redis缓存 + * @param key + * @return + */ + private static String getStringValue(String key){ + Object obj = getValue(key); + return ObjectUtils.isEmpty(obj) ? null : String.valueOf(obj); + } + + /*** + * 根据key获取redis缓存 + * @param key + * @return + */ + private static Object getValue(String key){ + RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class); + if(ObjectUtils.isEmpty(redisUtil)){ + log.error("SpringUtil.getRedisValue========== redisUtil is null"); + } + Object obj = redisUtil.get(key); + if(ObjectUtils.isEmpty(obj)){ + log.error("SpringUtil.getRedisValue=={}========== obj is null",key); + return null; + } + log.info("SpringUtil.getRedisValue=={}===={}",key,String.valueOf(obj)); + return obj; + } + +} diff --git a/wechat-server/src/main/java/com/evotech/hd/wechat/utils/permission/TokenUtil.java b/wechat-server/src/main/java/com/evotech/hd/wechat/utils/permission/TokenUtil.java new file mode 100644 index 0000000..f85fa52 --- /dev/null +++ b/wechat-server/src/main/java/com/evotech/hd/wechat/utils/permission/TokenUtil.java @@ -0,0 +1,56 @@ +package com.evotech.hd.wechat.utils.permission; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.jwt.JWT; +import cn.hutool.jwt.JWTUtil; +import org.springframework.security.oauth2.jwt.JwtClaimNames; + +import java.util.Date; + +/** + * token解析工具类 + */ +public class TokenUtil { + + + public static JWT parseToJwt(String token) { + JWT parseToken = JWTUtil.parseToken(token); + return parseToken; + } + + + /** + * 从token中获取userId + */ + public static String getUserId(String token) { + String uid = parseToJwt(token).getPayloads().getStr("uid"); + return uid; + } + + /** + * 从token中获取rcodes + */ + public static String getRcodes(String token) { + String uid = parseToJwt(token).getPayloads().getStr("rcodes"); + return uid; + } + + + /** + * 从token中获取jti + */ + public static String getJti(String token) { + String jti = parseToJwt(token).getPayloads().getStr(JwtClaimNames.JTI).replaceAll("-", ""); + return jti; + } + + + /** + * 从token中获取过期时间 + */ + public static Date getExp(String token) { + String exp = parseToJwt(token).getPayloads().getStr(JwtClaimNames.EXP).toString(); + return DateUtil.date(Long.valueOf(exp) * 1000); + } + +}