From ebb31ef0aba9ccda47a1d0817ed0945e48a9be84 Mon Sep 17 00:00:00 2001 From: Hccake Date: Sun, 5 Sep 2021 14:16:37 +0800 Subject: [PATCH 01/16] =?UTF-8?q?:fire:=20=E7=A7=BB=E9=99=A4=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pig-visual/pig-xxl-job-admin/pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pig-visual/pig-xxl-job-admin/pom.xml b/pig-visual/pig-xxl-job-admin/pom.xml index b894d181..68f19f08 100644 --- a/pig-visual/pig-xxl-job-admin/pom.xml +++ b/pig-visual/pig-xxl-job-admin/pom.xml @@ -47,12 +47,6 @@ spring-boot-starter-mail - - - org.springframework.boot - spring-boot-starter-actuator - - org.mybatis.spring.boot From e3a9995af40ff63ced5493b3a9e2cc3f8b3fb14e Mon Sep 17 00:00:00 2001 From: Hccake Date: Sun, 5 Sep 2021 15:06:06 +0800 Subject: [PATCH 02/16] =?UTF-8?q?:sparkles:=20=E7=A7=BB=E6=A4=8D=20ballcat?= =?UTF-8?q?=20=E7=9A=84=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90=E5=88=B0=20pig?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pig-common/pig-common-bom/pom.xml | 13 + pig-common/pig-common-datascope/pom.xml | 38 +++ .../pig/common/datascope/DataScope.java | 36 ++ .../datascope/DataScopeAutoConfiguration.java | 54 +++ .../datascope/annotation/DataPermission.java | 35 ++ .../handler/DataPermissionHandler.java | 35 ++ .../handler/DefaultDataPermissionHandler.java | 76 +++++ .../DataPermissionAnnotationHolder.java | 58 ++++ .../datascope/holder/DataScopeHolder.java | 41 +++ .../DataPermissionAnnotationAdvisor.java | 34 ++ .../DataPermissionAnnotationInterceptor.java | 35 ++ .../interceptor/DataPermissionFinder.java | 65 ++++ .../DataPermissionInterceptor.java | 72 ++++ .../datascope/parser/JsqlParserSupport.java | 114 +++++++ .../processor/DataScopeSqlProcessor.java | 321 ++++++++++++++++++ .../common/datascope/util/AnnotationUtil.java | 64 ++++ .../common/datascope/util/PluginUtils.java | 163 +++++++++ .../main/resources/META-INF/spring.factories | 3 + .../common/datascope/test/SqlParseTest.java | 75 ++++ pig-common/pom.xml | 3 +- 20 files changed, 1334 insertions(+), 1 deletion(-) create mode 100644 pig-common/pig-common-datascope/pom.xml create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/DataScope.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/DataScopeAutoConfiguration.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/annotation/DataPermission.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/handler/DataPermissionHandler.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/handler/DefaultDataPermissionHandler.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/holder/DataPermissionAnnotationHolder.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/holder/DataScopeHolder.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionAnnotationAdvisor.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionAnnotationInterceptor.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionFinder.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionInterceptor.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/parser/JsqlParserSupport.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/processor/DataScopeSqlProcessor.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/util/AnnotationUtil.java create mode 100644 pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/util/PluginUtils.java create mode 100644 pig-common/pig-common-datascope/src/main/resources/META-INF/spring.factories create mode 100644 pig-common/pig-common-datascope/src/test/java/com/pigcloud/pig/common/datascope/test/SqlParseTest.java diff --git a/pig-common/pig-common-bom/pom.xml b/pig-common/pig-common-bom/pom.xml index c3702648..5377bc29 100644 --- a/pig-common/pig-common-bom/pom.xml +++ b/pig-common/pig-common-bom/pom.xml @@ -25,6 +25,8 @@ 1.2.75 1.5.24 3.4.3.2 + 3.5.7 + 4.1 5.18.3 2.0.3 1.0.0 @@ -123,11 +125,22 @@ excel-spring-boot-starter ${excel.version} + com.baomidou mybatis-plus-boot-starter ${mybatis-plus.version} + + org.mybatis + mybatis + ${mybatis.version} + + + com.github.jsqlparser + jsqlparser + ${jsqlparser.version} + org.springframework.boot diff --git a/pig-common/pig-common-datascope/pom.xml b/pig-common/pig-common-datascope/pom.xml new file mode 100644 index 00000000..1a22953e --- /dev/null +++ b/pig-common/pig-common-datascope/pom.xml @@ -0,0 +1,38 @@ + + + + pig-common + com.pig4cloud + 3.3.3 + + 4.0.0 + + pig-common-datascope + + + + + org.slf4j + slf4j-api + + + com.github.jsqlparser + jsqlparser + + + org.mybatis + mybatis + + + org.springframework + spring-context + + + org.springframework.boot + spring-boot-autoconfigure + + + + \ No newline at end of file diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/DataScope.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/DataScope.java new file mode 100644 index 00000000..b137fd26 --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/DataScope.java @@ -0,0 +1,36 @@ +package com.pigcloud.pig.common.datascope; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; + +import java.util.Collection; + +/** + * @author Hccake 2020/9/28 + * @version 1.0 + */ +public interface DataScope { + + /** + * 数据所对应的资源 + * @return 资源标识 + */ + String getResource(); + + /** + * 该资源相关的所有表,推荐使用 Set 类型。
+ * 如需忽略表名大小写判断,则可以使用 TreeSet,并设置忽略大小写的自定义Comparator。
+ * eg. new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + * @return tableNames + */ + Collection getTableNames(); + + /** + * 根据表名和表别名,动态生成的 where/or 筛选条件 + * @param tableName 表名 + * @param tableAlias 表别名,可能为空 + * @return 数据规则表达式 + */ + Expression getExpression(String tableName, Alias tableAlias); + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/DataScopeAutoConfiguration.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/DataScopeAutoConfiguration.java new file mode 100644 index 00000000..6928850a --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/DataScopeAutoConfiguration.java @@ -0,0 +1,54 @@ +package com.pigcloud.pig.common.datascope; + +import com.pigcloud.pig.common.datascope.handler.DataPermissionHandler; +import com.pigcloud.pig.common.datascope.handler.DefaultDataPermissionHandler; +import com.pigcloud.pig.common.datascope.interceptor.DataPermissionAnnotationAdvisor; +import com.pigcloud.pig.common.datascope.interceptor.DataPermissionInterceptor; +import com.pigcloud.pig.common.datascope.processor.DataScopeSqlProcessor; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; + +import java.util.List; + +/** + * @author hccake + */ +@RequiredArgsConstructor +@ConditionalOnBean(DataScope.class) +public class DataScopeAutoConfiguration { + + /** + * 数据权限处理器 + * @param dataScopeList 需要控制的数据范围集合 + * @return DataPermissionHandler + */ + @Bean + @ConditionalOnMissingBean + public DataPermissionHandler dataPermissionHandler(List dataScopeList) { + return new DefaultDataPermissionHandler(dataScopeList); + } + + /** + * 数据权限注解 Advisor,用于处理数据权限的链式调用关系 + * @return DataPermissionAnnotationAdvisor + */ + @Bean + @ConditionalOnMissingBean(DataPermissionAnnotationAdvisor.class) + public DataPermissionAnnotationAdvisor dataPermissionAnnotationAdvisor() { + return new DataPermissionAnnotationAdvisor(); + } + + /** + * mybatis 拦截器,用于拦截处理 sql + * @param dataPermissionHandler 数据权限处理器 + * @return DataPermissionInterceptor + */ + @Bean + @ConditionalOnMissingBean + public DataPermissionInterceptor dataPermissionInterceptor(DataPermissionHandler dataPermissionHandler) { + return new DataPermissionInterceptor(new DataScopeSqlProcessor(), dataPermissionHandler); + } + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/annotation/DataPermission.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/annotation/DataPermission.java new file mode 100644 index 00000000..0c6ef980 --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/annotation/DataPermission.java @@ -0,0 +1,35 @@ +package com.pigcloud.pig.common.datascope.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限注解,注解在 Mapper类 或者 对应方法上 用于提供该 mapper 对应表,所需控制的实体信息 + * @author Hccake 2020/9/27 + * @version 1.0 + */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataPermission { + + /** + * 当前类或方法是否忽略数据权限 + * @return boolean 默认返回 false + */ + boolean ignore() default false; + + /** + * 仅对指定资源类型进行数据权限控制,只在开启情况下有效,当该数组有值时,exclude不生效 + * @see DataPermission#excludeResources + * @return 资源类型数组 + */ + String[] includeResources() default {}; + + /** + * 对指定资源类型跳过数据权限控制,只在开启情况下有效,当该includeResources有值时,exclude不生效 + * @see DataPermission#includeResources + * @return 资源类型数组 + */ + String[] excludeResources() default {}; + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/handler/DataPermissionHandler.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/handler/DataPermissionHandler.java new file mode 100644 index 00000000..a5620000 --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/handler/DataPermissionHandler.java @@ -0,0 +1,35 @@ +package com.pigcloud.pig.common.datascope.handler; + +import com.pigcloud.pig.common.datascope.DataScope; + +import java.util.List; + +/** + * 数据权限处理器 + * + * @author Hccake 2020/9/28 + * @version 1.0 + */ +public interface DataPermissionHandler { + + /** + * 系统配置的所有的数据范围 + * @return 数据范围集合 + */ + List dataScopes(); + + /** + * 根据权限注解过滤后的数据范围集合 + * @param mappedStatementId Mapper方法ID + * @return 数据范围集合 + */ + List filterDataScopes(String mappedStatementId); + + /** + * 是否忽略权限控制,用于及早的忽略控制,例如管理员直接放行,而不必等到DataScope中再进行过滤处理,提升效率 + * @return boolean true: 忽略,false: 进行权限控制 + * @param mappedStatementId Mapper方法ID + */ + boolean ignorePermissionControl(String mappedStatementId); + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/handler/DefaultDataPermissionHandler.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/handler/DefaultDataPermissionHandler.java new file mode 100644 index 00000000..4622936e --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/handler/DefaultDataPermissionHandler.java @@ -0,0 +1,76 @@ +package com.pigcloud.pig.common.datascope.handler; + +import com.pigcloud.pig.common.datascope.DataScope; +import com.pigcloud.pig.common.datascope.annotation.DataPermission; +import com.pigcloud.pig.common.datascope.holder.DataPermissionAnnotationHolder; +import lombok.RequiredArgsConstructor; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 默认的数据权限控制处理器 + * + * @author Hccake 2021/1/27 + * @version 1.0 + */ +@RequiredArgsConstructor +public class DefaultDataPermissionHandler implements DataPermissionHandler { + + private final List dataScopes; + + /** + * 系统配置的所有的数据范围 + * @return 数据范围集合 + */ + @Override + public List dataScopes() { + return dataScopes; + } + + /** + * 系统配置的所有的数据范围 + * @param mappedStatementId Mapper方法ID + * @return 数据范围集合 + */ + @Override + public List filterDataScopes(String mappedStatementId) { + if (this.dataScopes == null || this.dataScopes.isEmpty()) { + return new ArrayList<>(); + } + // 获取当前方法对应的权限注解,根据注解进行数据范围控制的过滤 + DataPermission dataPermission = DataPermissionAnnotationHolder.peek(); + if (dataPermission == null) { + return dataScopes; + } + + if (dataPermission.ignore()) { + return new ArrayList<>(); + } + + // 当指定了只包含的资源时,只对该资源的DataScope + if (dataPermission.includeResources().length > 0) { + Set a = new HashSet<>(Arrays.asList(dataPermission.includeResources())); + return dataScopes.stream().filter(x -> a.contains(x.getResource())).collect(Collectors.toList()); + } + + // 当未指定只包含的资源,且指定了排除的资源时,则排除此部分资源的 DataScope + if (dataPermission.excludeResources().length > 0) { + Set a = new HashSet<>(Arrays.asList(dataPermission.excludeResources())); + return dataScopes.stream().filter(x -> !a.contains(x.getResource())).collect(Collectors.toList()); + } + + return dataScopes; + } + + /** + * 是否忽略权限控制,默认不忽略 + * @param mappedStatementId Mapper方法ID + * @return always false + */ + @Override + public boolean ignorePermissionControl(String mappedStatementId) { + return false; + } + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/holder/DataPermissionAnnotationHolder.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/holder/DataPermissionAnnotationHolder.java new file mode 100644 index 00000000..7ceb63b5 --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/holder/DataPermissionAnnotationHolder.java @@ -0,0 +1,58 @@ +package com.pigcloud.pig.common.datascope.holder; + +import com.pigcloud.pig.common.datascope.annotation.DataPermission; + +import java.util.ArrayDeque; +import java.util.Deque; + +/** + * 数据权限注解的持有者,使用栈存储调用链中各方法对应数据权限注解 + * + * @author hccake + */ +public final class DataPermissionAnnotationHolder { + + private DataPermissionAnnotationHolder() { + } + + /** + * 使用栈存储 DataPermission,便于在方法嵌套调用时使用不同的数据权限控制。 + */ + private static final ThreadLocal> DATA_PERMISSIONS = ThreadLocal.withInitial(ArrayDeque::new); + + /** + * 获取当前的 DataPermission 注解 + * @return DataPermission + */ + public static DataPermission peek() { + return DATA_PERMISSIONS.get().peek(); + } + + /** + * 入栈一个 DataPermission 注解 + * @return DataPermission + */ + public static DataPermission push(DataPermission dataPermission) { + DATA_PERMISSIONS.get().push(dataPermission); + return dataPermission; + } + + /** + * 弹出最顶部 DataPermission + */ + public static void poll() { + Deque deque = DATA_PERMISSIONS.get(); + // 当没有元素时,清空 ThreadLocal + if (deque.poll() == null) { + DATA_PERMISSIONS.remove(); + } + } + + /** + * 清除 TreadLocal + */ + public static void clear() { + DATA_PERMISSIONS.remove(); + } + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/holder/DataScopeHolder.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/holder/DataScopeHolder.java new file mode 100644 index 00000000..e47dad32 --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/holder/DataScopeHolder.java @@ -0,0 +1,41 @@ +package com.pigcloud.pig.common.datascope.holder; + +import com.pigcloud.pig.common.datascope.DataScope; + +import java.util.List; + +/** + * DataScope 持有者。 方便解析 SQL 时的参数透传 + * + * @author hccake + */ +public final class DataScopeHolder { + + private DataScopeHolder() { + } + + private static final ThreadLocal> DATA_SCOPES = new ThreadLocal<>(); + + /** + * get dataScope + * @return dataScopes + */ + public static List get() { + return DATA_SCOPES.get(); + } + + /** + * 添加 dataScope + */ + public static void set(List dataScopes) { + DATA_SCOPES.set(dataScopes); + } + + /** + * 删除 dataScope + */ + public static void remove() { + DATA_SCOPES.remove(); + } + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionAnnotationAdvisor.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionAnnotationAdvisor.java new file mode 100644 index 00000000..f333d697 --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionAnnotationAdvisor.java @@ -0,0 +1,34 @@ +package com.pigcloud.pig.common.datascope.interceptor; + +import com.pigcloud.pig.common.datascope.annotation.DataPermission; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.aopalliance.aop.Advice; +import org.springframework.aop.Pointcut; +import org.springframework.aop.support.AbstractPointcutAdvisor; +import org.springframework.aop.support.ComposablePointcut; +import org.springframework.aop.support.annotation.AnnotationMatchingPointcut; + +/** + * @author hccake + */ +@Getter +@EqualsAndHashCode(callSuper = true) +public class DataPermissionAnnotationAdvisor extends AbstractPointcutAdvisor { + + private final Advice advice; + + private final Pointcut pointcut; + + public DataPermissionAnnotationAdvisor() { + this.advice = new DataPermissionAnnotationInterceptor(); + this.pointcut = buildPointcut(); + } + + protected Pointcut buildPointcut() { + Pointcut cpc = new AnnotationMatchingPointcut(DataPermission.class, true); + Pointcut mpc = new AnnotationMatchingPointcut(null, DataPermission.class, true); + return new ComposablePointcut(cpc).union(mpc); + } + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionAnnotationInterceptor.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionAnnotationInterceptor.java new file mode 100644 index 00000000..b9ae8fdf --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionAnnotationInterceptor.java @@ -0,0 +1,35 @@ +package com.pigcloud.pig.common.datascope.interceptor; + +import com.pigcloud.pig.common.datascope.annotation.DataPermission; +import com.pigcloud.pig.common.datascope.holder.DataPermissionAnnotationHolder; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import java.lang.reflect.Method; + +/** + * DataPermission注解的拦截器,在执行方法前将当前方法的对应注解压栈,执行后弹出注解 + * + * @author hccake + */ +public class DataPermissionAnnotationInterceptor implements MethodInterceptor { + + @Override + public Object invoke(MethodInvocation methodInvocation) throws Throwable { + // 当前方法 + Method method = methodInvocation.getMethod(); + // 获取执行类 + Object invocationThis = methodInvocation.getThis(); + Class clazz = invocationThis != null ? invocationThis.getClass() : method.getDeclaringClass(); + // 寻找对应的 DataPermission 注解属性 + DataPermission dataPermission = DataPermissionFinder.findDataPermission(method, clazz); + DataPermissionAnnotationHolder.push(dataPermission); + try { + return methodInvocation.proceed(); + } + finally { + DataPermissionAnnotationHolder.poll(); + } + } + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionFinder.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionFinder.java new file mode 100644 index 00000000..1d4d1e30 --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionFinder.java @@ -0,0 +1,65 @@ +package com.pigcloud.pig.common.datascope.interceptor; + +import com.pigcloud.pig.common.datascope.annotation.DataPermission; +import org.springframework.core.MethodClassKey; +import org.springframework.core.annotation.AnnotatedElementUtils; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * {@link DataPermission} 注解的查找者。用于查询当前方法对应的 DataPermission 注解环境,当方法上没有找到时,会去类上寻找。 + * + * @author hccake + */ +@DataPermission +public final class DataPermissionFinder { + + private DataPermissionFinder() { + + } + + private static final Map DATA_PERMISSION_CACHE = new ConcurrentHashMap<>(1024); + + /** + * 提供一个默认的空值注解,用于缓存空值占位使用 + */ + private static final DataPermission EMPTY_DATA_PERMISSION = DataPermissionFinder.class + .getAnnotation(DataPermission.class); + + /** + * 缓存的 key 值 + * @param method 方法 + * @param clazz 类 + * @return key + */ + private static Object getCacheKey(Method method, Class clazz) { + return new MethodClassKey(method, clazz); + } + + /** + * 从缓存中获取数据权限注解 优先获取方法上的注解,再获取类上的注解 + * @param method 当前方法 + * @param clazz 当前类 + * @return 当前方法有效的数据权限注解 + */ + public static DataPermission findDataPermission(Method method, Class clazz) { + Object methodKey = getCacheKey(method, clazz); + + if (DATA_PERMISSION_CACHE.containsKey(methodKey)) { + DataPermission dataPermission = DATA_PERMISSION_CACHE.get(methodKey); + // 判断是否和缓存的空注解是同一个对象 + return EMPTY_DATA_PERMISSION == dataPermission ? null : dataPermission; + } + + // 先查方法,如果方法上没有,则使用类上 + DataPermission dataPermission = AnnotatedElementUtils.findMergedAnnotation(method, DataPermission.class); + if (dataPermission == null) { + dataPermission = AnnotatedElementUtils.findMergedAnnotation(clazz, DataPermission.class); + } + DATA_PERMISSION_CACHE.put(methodKey, dataPermission == null ? EMPTY_DATA_PERMISSION : dataPermission); + return dataPermission; + } + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionInterceptor.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionInterceptor.java new file mode 100644 index 00000000..9caba7ba --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/interceptor/DataPermissionInterceptor.java @@ -0,0 +1,72 @@ +package com.pigcloud.pig.common.datascope.interceptor; + +import com.pigcloud.pig.common.datascope.DataScope; +import com.pigcloud.pig.common.datascope.handler.DataPermissionHandler; +import com.pigcloud.pig.common.datascope.processor.DataScopeSqlProcessor; +import com.pigcloud.pig.common.datascope.util.PluginUtils; +import lombok.RequiredArgsConstructor; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.plugin.*; + +import java.sql.Connection; +import java.util.List; + +/** + * 数据权限拦截器 + * + * @author Hccake 2020/9/28 + * @version 1.0 + */ +@RequiredArgsConstructor +@Intercepts({ + @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) }) +public class DataPermissionInterceptor implements Interceptor { + + private final DataScopeSqlProcessor dataScopeSqlProcessor; + + private final DataPermissionHandler dataPermissionHandler; + + @Override + public Object intercept(Invocation invocation) throws Throwable { + // 第一版,测试用 + Object target = invocation.getTarget(); + StatementHandler sh = (StatementHandler) target; + PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); + MappedStatement ms = mpSh.mappedStatement(); + SqlCommandType sct = ms.getSqlCommandType(); + PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); + String mappedStatementId = ms.getId(); + + // 根据用户权限判断是否需要拦截,例如管理员可以查看所有,则直接放行 + if (dataPermissionHandler.ignorePermissionControl(mappedStatementId)) { + return invocation.proceed(); + } + + List dataScopes = dataPermissionHandler.filterDataScopes(mappedStatementId); + if (dataScopes == null || dataScopes.isEmpty()) { + return invocation.proceed(); + } + + // 根据 DataScopes 进行数据权限的 sql 处理 + if (sct == SqlCommandType.SELECT) { + mpBs.sql(dataScopeSqlProcessor.parserSingle(mpBs.sql(), dataScopes)); + } + else if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { + mpBs.sql(dataScopeSqlProcessor.parserMulti(mpBs.sql(), dataScopes)); + } + + // 执行 sql + return invocation.proceed(); + } + + @Override + public Object plugin(Object target) { + if (target instanceof StatementHandler) { + return Plugin.wrap(target, this); + } + return target; + } + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/parser/JsqlParserSupport.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/parser/JsqlParserSupport.java new file mode 100644 index 00000000..ab12c2ed --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/parser/JsqlParserSupport.java @@ -0,0 +1,114 @@ +package com.pigcloud.pig.common.datascope.parser; + +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.Statements; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.update.Update; + +/** + * https://github.com/JSQLParser/JSqlParser + * + * @author miemie hccake + * @since 2020-06-22 + */ +@Slf4j +public abstract class JsqlParserSupport { + + public String parserSingle(String sql, Object obj) { + if (log.isDebugEnabled()) { + log.debug("original SQL: " + sql); + } + try { + Statement statement = CCJSqlParserUtil.parse(sql); + return processParser(statement, 0, sql, obj); + } + catch (JSQLParserException e) { + throw new RuntimeException(String.format("Failed to process, Error SQL: %s", sql), e); + } + } + + public String parserMulti(String sql, Object obj) { + if (log.isDebugEnabled()) { + log.debug("original SQL: " + sql); + } + try { + // fixed github pull/295 + StringBuilder sb = new StringBuilder(); + Statements statements = CCJSqlParserUtil.parseStatements(sql); + int i = 0; + for (Statement statement : statements.getStatements()) { + if (i > 0) { + sb.append(";"); + } + sb.append(processParser(statement, i, sql, obj)); + i++; + } + return sb.toString(); + } + catch (JSQLParserException e) { + throw new RuntimeException(String.format("Failed to process, Error SQL: %s", sql), e); + } + } + + /** + * 执行 SQL 解析 + * @param statement JsqlParser Statement + * @return sql + */ + protected String processParser(Statement statement, int index, String sql, Object obj) { + if (log.isDebugEnabled()) { + log.debug("SQL to parse, SQL: " + sql); + } + if (statement instanceof Insert) { + this.processInsert((Insert) statement, index, sql, obj); + } + else if (statement instanceof Select) { + this.processSelect((Select) statement, index, sql, obj); + } + else if (statement instanceof Update) { + this.processUpdate((Update) statement, index, sql, obj); + } + else if (statement instanceof Delete) { + this.processDelete((Delete) statement, index, sql, obj); + } + sql = statement.toString(); + if (log.isDebugEnabled()) { + log.debug("parse the finished SQL: " + sql); + } + return sql; + } + + /** + * 新增 + */ + protected void processInsert(Insert insert, int index, String sql, Object obj) { + throw new UnsupportedOperationException(); + } + + /** + * 删除 + */ + protected void processDelete(Delete delete, int index, String sql, Object obj) { + throw new UnsupportedOperationException(); + } + + /** + * 更新 + */ + protected void processUpdate(Update update, int index, String sql, Object obj) { + throw new UnsupportedOperationException(); + } + + /** + * 查询 + */ + protected void processSelect(Select select, int index, String sql, Object obj) { + throw new UnsupportedOperationException(); + } + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/processor/DataScopeSqlProcessor.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/processor/DataScopeSqlProcessor.java new file mode 100644 index 00000000..7248be92 --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/processor/DataScopeSqlProcessor.java @@ -0,0 +1,321 @@ +package com.pigcloud.pig.common.datascope.processor; + +import com.pigcloud.pig.common.datascope.DataScope; +import com.pigcloud.pig.common.datascope.holder.DataScopeHolder; +import com.pigcloud.pig.common.datascope.parser.JsqlParserSupport; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.expression.*; +import net.sf.jsqlparser.expression.operators.conditional.AndExpression; +import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +import net.sf.jsqlparser.expression.operators.relational.ExistsExpression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.InExpression; +import net.sf.jsqlparser.expression.operators.relational.ItemsList; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.select.*; +import net.sf.jsqlparser.statement.update.Update; + +import java.util.List; +import java.util.Objects; + +/** + * 数据权限 sql 处理器 参考 mybatis-plus 租户拦截器,解析 sql where 部分,进行查询表达式注入 + * + * @author Hccake 2020/9/26 + * @version 1.0 + */ +@RequiredArgsConstructor +@Slf4j +public class DataScopeSqlProcessor extends JsqlParserSupport { + + /** + * select 类型SQL处理 + * @param select jsqlparser Statement Select + */ + @Override + protected void processSelect(Select select, int index, String sql, Object obj) { + List dataScopes = (List) obj; + try { + // dataScopes 放入 ThreadLocal 方便透传 + DataScopeHolder.set(dataScopes); + processSelectBody(select.getSelectBody()); + List withItemsList = select.getWithItemsList(); + if (withItemsList != null && !withItemsList.isEmpty()) { + withItemsList.forEach(this::processSelectBody); + } + } + finally { + // 必须清空 ThreadLocal + DataScopeHolder.remove(); + } + } + + protected void processSelectBody(SelectBody selectBody) { + if (selectBody == null) { + return; + } + if (selectBody instanceof PlainSelect) { + processPlainSelect((PlainSelect) selectBody); + } + else if (selectBody instanceof WithItem) { + WithItem withItem = (WithItem) selectBody; + processSelectBody(withItem.getSubSelect().getSelectBody()); + } + else { + SetOperationList operationList = (SetOperationList) selectBody; + List selectBodys = operationList.getSelects(); + if (selectBodys != null && !selectBodys.isEmpty()) { + selectBodys.forEach(this::processSelectBody); + } + } + } + + /** + * insert 类型SQL处理 + * @param insert jsqlparser Statement Insert + */ + @Override + protected void processInsert(Insert insert, int index, String sql, Object obj) { + // insert 暂时不处理 + } + + /** + * update 类型SQL处理 + * @param update jsqlparser Statement Update + */ + @Override + protected void processUpdate(Update update, int index, String sql, Object obj) { + List dataScopes = (List) obj; + try { + // dataScopes 放入 ThreadLocal 方便透传 + DataScopeHolder.set(dataScopes); + update.setWhere(this.injectExpression(update.getWhere(), update.getTable())); + } + finally { + // 必须清空 ThreadLocal + DataScopeHolder.remove(); + } + } + + /** + * delete 类型SQL处理 + * @param delete jsqlparser Statement Delete + */ + @Override + protected void processDelete(Delete delete, int index, String sql, Object obj) { + List dataScopes = (List) obj; + try { + // dataScopes 放入 ThreadLocal 方便透传 + DataScopeHolder.set(dataScopes); + delete.setWhere(this.injectExpression(delete.getWhere(), delete.getTable())); + } + finally { + // 必须清空 ThreadLocal + DataScopeHolder.remove(); + } + } + + /** + * 处理 PlainSelect + */ + protected void processPlainSelect(PlainSelect plainSelect) { + FromItem fromItem = plainSelect.getFromItem(); + Expression where = plainSelect.getWhere(); + processWhereSubSelect(where); + if (fromItem instanceof Table) { + Table fromTable = (Table) fromItem; + // #1186 github + plainSelect.setWhere(injectExpression(where, fromTable)); + } + else { + processFromItem(fromItem); + } + // #3087 github + List selectItems = plainSelect.getSelectItems(); + if (selectItems != null && !selectItems.isEmpty()) { + selectItems.forEach(this::processSelectItem); + } + List joins = plainSelect.getJoins(); + if (joins != null && !joins.isEmpty()) { + joins.forEach(j -> { + processJoin(j); + processFromItem(j.getRightItem()); + }); + } + } + + /** + * 处理where条件内的子查询 + *

+ * 支持如下: 1. in 2. = 3. > 4. < 5. >= 6. <= 7. <> 8. EXISTS 9. NOT EXISTS + *

+ * 前提条件: 1. 子查询必须放在小括号中 2. 子查询一般放在比较操作符的右边 + * @param where where 条件 + */ + protected void processWhereSubSelect(Expression where) { + if (where == null) { + return; + } + if (where instanceof FromItem) { + processFromItem((FromItem) where); + return; + } + if (where.toString().indexOf("SELECT") > 0) { + // 有子查询 + if (where instanceof BinaryExpression) { + // 比较符号 , and , or , 等等 + BinaryExpression expression = (BinaryExpression) where; + processWhereSubSelect(expression.getLeftExpression()); + processWhereSubSelect(expression.getRightExpression()); + } + else if (where instanceof InExpression) { + // in + InExpression expression = (InExpression) where; + ItemsList itemsList = expression.getRightItemsList(); + if (itemsList instanceof SubSelect) { + processSelectBody(((SubSelect) itemsList).getSelectBody()); + } + } + else if (where instanceof ExistsExpression) { + // exists + ExistsExpression expression = (ExistsExpression) where; + processWhereSubSelect(expression.getRightExpression()); + } + else if (where instanceof NotExpression) { + // not exists + NotExpression expression = (NotExpression) where; + processWhereSubSelect(expression.getExpression()); + } + else if (where instanceof Parenthesis) { + Parenthesis expression = (Parenthesis) where; + processWhereSubSelect(expression.getExpression()); + } + } + } + + protected void processSelectItem(SelectItem selectItem) { + if (selectItem instanceof SelectExpressionItem) { + SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem; + if (selectExpressionItem.getExpression() instanceof SubSelect) { + processSelectBody(((SubSelect) selectExpressionItem.getExpression()).getSelectBody()); + } + else if (selectExpressionItem.getExpression() instanceof Function) { + processFunction((Function) selectExpressionItem.getExpression()); + } + } + } + + /** + * 处理函数 + *

+ * 支持: 1. select fun(args..) 2. select fun1(fun2(args..),args..) + *

+ *

+ * fixed gitee pulls/141 + *

+ * @param function + */ + protected void processFunction(Function function) { + ExpressionList parameters = function.getParameters(); + if (parameters != null) { + parameters.getExpressions().forEach(expression -> { + if (expression instanceof SubSelect) { + processSelectBody(((SubSelect) expression).getSelectBody()); + } + else if (expression instanceof Function) { + processFunction((Function) expression); + } + }); + } + } + + /** + * 处理子查询等 + */ + protected void processFromItem(FromItem fromItem) { + if (fromItem instanceof SubJoin) { + SubJoin subJoin = (SubJoin) fromItem; + if (subJoin.getJoinList() != null) { + subJoin.getJoinList().forEach(this::processJoin); + } + if (subJoin.getLeft() != null) { + processFromItem(subJoin.getLeft()); + } + } + else if (fromItem instanceof SubSelect) { + SubSelect subSelect = (SubSelect) fromItem; + if (subSelect.getSelectBody() != null) { + processSelectBody(subSelect.getSelectBody()); + } + } + else if (fromItem instanceof ValuesList) { + log.debug("Perform a subquery, if you do not give us feedback"); + } + else if (fromItem instanceof LateralSubSelect) { + LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem; + if (lateralSubSelect.getSubSelect() != null) { + SubSelect subSelect = lateralSubSelect.getSubSelect(); + if (subSelect.getSelectBody() != null) { + processSelectBody(subSelect.getSelectBody()); + } + } + } + } + + /** + * 处理联接语句 + */ + protected void processJoin(Join join) { + if (join.getRightItem() instanceof Table) { + Table fromTable = (Table) join.getRightItem(); + join.setOnExpression(injectExpression(join.getOnExpression(), fromTable)); + } + } + + /** + * 根据 DataScope ,将数据过滤的表达式注入原本的 where/or 条件 + * @param currentExpression Expression where/or + * @param table 表信息 + * @return 修改后的 where/or 条件 + */ + private Expression injectExpression(Expression currentExpression, Table table) { + String tableName = table.getName(); + List dataScopes = DataScopeHolder.get(); + Expression dataFilterExpression = dataScopes.stream().filter(x -> x.getTableNames().contains(tableName)) + .map(x -> x.getExpression(tableName, table.getAlias())).filter(Objects::nonNull) + .reduce(AndExpression::new).orElse(null); + + if (currentExpression == null) { + return dataFilterExpression; + } + if (dataFilterExpression == null) { + return currentExpression; + } + if (currentExpression instanceof OrExpression) { + return new AndExpression(new Parenthesis(currentExpression), dataFilterExpression); + } + else { + return new AndExpression(currentExpression, dataFilterExpression); + } + } + + /** + * 根据当前表是否有别名,动态对字段名前添加表别名 eg. 表名: table_1 as t 原始字段:column1 返回: t.column1 + * @param table 表信息 + * @param column 字段名 + * @return 原始字段名,或者添加了表别名的字段名 + */ + protected Column getAliasColumn(Table table, String column) { + StringBuilder columnBuilder = new StringBuilder(); + if (table.getAlias() != null) { + columnBuilder.append(table.getAlias().getName()).append("."); + } + columnBuilder.append(column); + return new Column(columnBuilder.toString()); + } + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/util/AnnotationUtil.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/util/AnnotationUtil.java new file mode 100644 index 00000000..ccead3ff --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/util/AnnotationUtil.java @@ -0,0 +1,64 @@ +package com.pigcloud.pig.common.datascope.util; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +/** + * @author Hccake 2021/1/27 + * @version 1.0 + */ +public final class AnnotationUtil { + + private AnnotationUtil() { + } + + /** + * 获取数据权限注解 优先获取方法上的注解,再获取类上的注解 + * @param mappedStatementId 类名.方法名 + * @return 数据权限注解 + */ + public static A findAnnotationByMappedStatementId(String mappedStatementId, + Class aClass) { + if (mappedStatementId == null || "".equals(mappedStatementId)) { + return null; + } + // 1.得到类路径和方法路径 + int lastIndexOfDot = mappedStatementId.lastIndexOf("."); + if (lastIndexOfDot < 0) { + return null; + } + String className = mappedStatementId.substring(0, lastIndexOfDot); + String methodName = mappedStatementId.substring(lastIndexOfDot + 1); + if ("".equals(className) || "".equals(methodName)) { + return null; + } + + // 2.字节码 + Class clazz = null; + try { + clazz = Class.forName(className); + } + catch (ClassNotFoundException e) { + e.printStackTrace(); + } + if (clazz == null) { + return null; + } + + A annotation = null; + // 3.得到方法上的注解 + Method[] methods = clazz.getMethods(); + for (Method method : methods) { + String name = method.getName(); + if (methodName.equals(name)) { + annotation = method.getAnnotation(aClass); + break; + } + } + if (annotation == null) { + annotation = clazz.getAnnotation(aClass); + } + return annotation; + } + +} diff --git a/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/util/PluginUtils.java b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/util/PluginUtils.java new file mode 100644 index 00000000..f4eca99f --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/java/com/pigcloud/pig/common/datascope/util/PluginUtils.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2011-2020, baomidou (jobob@qq.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.pigcloud.pig.common.datascope.util; + +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.executor.parameter.ParameterHandler; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.ParameterMapping; +import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.SystemMetaObject; +import org.apache.ibatis.session.Configuration; + +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 插件工具类 + * + * @author TaoYu , hubin + * @since 2017-06-20 + */ +public abstract class PluginUtils { + + public static final String DELEGATE_BOUNDSQL_SQL = "delegate.boundSql.sql"; + + /** + * 获得真正的处理对象,可能多层代理. + */ + @SuppressWarnings("unchecked") + public static T realTarget(Object target) { + if (Proxy.isProxyClass(target.getClass())) { + MetaObject metaObject = SystemMetaObject.forObject(target); + return realTarget(metaObject.getValue("h.target")); + } + return (T) target; + } + + /** + * 给 BoundSql 设置 additionalParameters + * @param boundSql BoundSql + * @param additionalParameters additionalParameters + */ + public static void setAdditionalParameter(BoundSql boundSql, Map additionalParameters) { + additionalParameters.forEach(boundSql::setAdditionalParameter); + } + + public static MPBoundSql mpBoundSql(BoundSql boundSql) { + return new MPBoundSql(boundSql); + } + + public static MPStatementHandler mpStatementHandler(StatementHandler statementHandler) { + statementHandler = realTarget(statementHandler); + MetaObject object = SystemMetaObject.forObject(statementHandler); + return new MPStatementHandler(SystemMetaObject.forObject(object.getValue("delegate"))); + } + + /** + * {@link org.apache.ibatis.executor.statement.BaseStatementHandler} + */ + public static class MPStatementHandler { + + private final MetaObject statementHandler; + + MPStatementHandler(MetaObject statementHandler) { + this.statementHandler = statementHandler; + } + + public ParameterHandler parameterHandler() { + return get("parameterHandler"); + } + + public MappedStatement mappedStatement() { + return get("mappedStatement"); + } + + public Executor executor() { + return get("executor"); + } + + public MPBoundSql mPBoundSql() { + return new MPBoundSql(boundSql()); + } + + public BoundSql boundSql() { + return get("boundSql"); + } + + public Configuration configuration() { + return get("configuration"); + } + + @SuppressWarnings("unchecked") + private T get(String property) { + return (T) statementHandler.getValue(property); + } + + } + + /** + * {@link BoundSql} + */ + public static class MPBoundSql { + + private final MetaObject boundSql; + + private final BoundSql delegate; + + MPBoundSql(BoundSql boundSql) { + this.delegate = boundSql; + this.boundSql = SystemMetaObject.forObject(boundSql); + } + + public String sql() { + return delegate.getSql(); + } + + public void sql(String sql) { + boundSql.setValue("sql", sql); + } + + public List parameterMappings() { + List parameterMappings = delegate.getParameterMappings(); + return new ArrayList<>(parameterMappings); + } + + public void parameterMappings(List parameterMappings) { + boundSql.setValue("parameterMappings", Collections.unmodifiableList(parameterMappings)); + } + + public Object parameterObject() { + return get("parameterObject"); + } + + public Map additionalParameters() { + return get("additionalParameters"); + } + + @SuppressWarnings("unchecked") + private T get(String property) { + return (T) boundSql.getValue(property); + } + + } + +} diff --git a/pig-common/pig-common-datascope/src/main/resources/META-INF/spring.factories b/pig-common/pig-common-datascope/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..7437931e --- /dev/null +++ b/pig-common/pig-common-datascope/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.pigcloud.pig.common.datascope.DataScopeAutoConfiguration + diff --git a/pig-common/pig-common-datascope/src/test/java/com/pigcloud/pig/common/datascope/test/SqlParseTest.java b/pig-common/pig-common-datascope/src/test/java/com/pigcloud/pig/common/datascope/test/SqlParseTest.java new file mode 100644 index 00000000..9fdf2dc5 --- /dev/null +++ b/pig-common/pig-common-datascope/src/test/java/com/pigcloud/pig/common/datascope/test/SqlParseTest.java @@ -0,0 +1,75 @@ +package com.pigcloud.pig.common.datascope.test; + +import com.pigcloud.pig.common.datascope.DataScope; +import com.pigcloud.pig.common.datascope.handler.DefaultDataPermissionHandler; +import com.pigcloud.pig.common.datascope.handler.DataPermissionHandler; +import com.pigcloud.pig.common.datascope.processor.DataScopeSqlProcessor; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; +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 org.junit.jupiter.api.Test; +import org.springframework.util.Assert; + +import java.util.*; + +/** + * @author Hccake 2020/9/28 + * @version 1.0 + */ +class SqlParseTest { + + @Test + void test() { + DataScope dataScope = new DataScope() { + final String columnId = "order_id"; + + @Override + public String getResource() { + return "order"; + } + + @Override + public Collection getTableNames() { + Set tableNames = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + tableNames.addAll(Arrays.asList("t_order", "t_order_info")); + return tableNames; + } + + @Override + public Expression getExpression(String tableName, Alias tableAlias) { + Column column = new Column(tableAlias == null ? columnId : tableAlias.getName() + "." + columnId); + ExpressionList expressionList = new ExpressionList(); + expressionList.setExpressions(Arrays.asList(new StringValue("1"), new StringValue("2"))); + return new InExpression(column, expressionList); + } + }; + + List dataScopes = new ArrayList<>(); + dataScopes.add(dataScope); + + DataPermissionHandler dataPermissionHandler = new DefaultDataPermissionHandler(dataScopes) { + @Override + public boolean ignorePermissionControl(String mappedStatementId) { + return false; + } + }; + + DataScopeSqlProcessor dataScopeSqlProcessor = new DataScopeSqlProcessor(); + + // DataScopeHolder.putDataScope("order", dataScope); + + String sql = "select o.order_id,o.order_name,oi.order_price " + + "from t_ORDER o left join t_order_info oi on o.order_id = oi.order_id " + + "where oi.order_price > 100"; + + String parseSql = dataScopeSqlProcessor.parserSingle(sql, dataPermissionHandler.dataScopes()); + System.out.println(parseSql); + + String trueSql = "SELECT o.order_id, o.order_name, oi.order_price FROM t_ORDER o LEFT JOIN t_order_info oi ON o.order_id = oi.order_id AND oi.order_id IN ('1', '2') WHERE oi.order_price > 100 AND o.order_id IN ('1', '2')"; + Assert.isTrue(trueSql.equals(parseSql), "sql 数据权限解析异常"); + } + +} diff --git a/pig-common/pom.xml b/pig-common/pom.xml index c16a61e2..edabd645 100755 --- a/pig-common/pom.xml +++ b/pig-common/pom.xml @@ -40,5 +40,6 @@ pig-common-feign pig-common-swagger pig-common-test - + pig-common-datascope + From 32a1ad61581f462ee81328db7a77807083297fa2 Mon Sep 17 00:00:00 2001 From: Hccake Date: Sat, 11 Sep 2021 19:03:47 +0800 Subject: [PATCH 03/16] =?UTF-8?q?:zap:=20=E7=99=BB=E5=BD=95=E6=97=B6?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=9A=84=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=A1=AB=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pig-common/pig-common-bom/pom.xml | 5 + .../constant/enums/DataScopeTypeEnum.java | 49 ++++++++ .../PigUserAuthenticationConverter.java | 3 +- .../datascope/DataScopeProcessor.java | 21 ++++ .../datascope/PigDataScopeProcessor.java | 119 ++++++++++++++++++ .../security/datascope/UserDataScope.java | 35 ++++++ .../pig/common/security/service/PigUser.java | 14 ++- .../service/PigUserDetailsServiceImpl.java | 14 ++- .../main/resources/META-INF/spring.factories | 3 +- .../pig4cloud/pig/admin/api/dto/UserInfo.java | 9 ++ .../pig/admin/api/entity/SysRole.java | 8 ++ .../admin/api/feign/RemoteDeptService.java | 45 +++++++ .../admin/api/feign/RemoteUserService.java | 14 +++ .../RemoteDeptServiceFallbackFactory.java | 37 ++++++ .../RemoteDeptServiceFallbackImpl.java | 45 +++++++ .../RemoteUserServiceFallbackImpl.java | 9 ++ .../pig/admin/api/vo/UserInfoVO.java | 49 ++++++++ pig-upms/pig-upms-biz/pom.xml | 5 + .../pig/admin/controller/DeptController.java | 12 ++ .../pig/admin/controller/UserController.java | 31 ++++- .../pig/admin/service/SysDeptService.java | 7 ++ .../pig/admin/service/SysUserService.java | 8 ++ .../service/impl/SysDeptServiceImpl.java | 11 ++ .../service/impl/SysUserServiceImpl.java | 20 ++- 24 files changed, 560 insertions(+), 13 deletions(-) create mode 100644 pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/enums/DataScopeTypeEnum.java create mode 100644 pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/datascope/DataScopeProcessor.java create mode 100644 pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/datascope/PigDataScopeProcessor.java create mode 100644 pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/datascope/UserDataScope.java create mode 100644 pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteDeptService.java create mode 100644 pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/factory/RemoteDeptServiceFallbackFactory.java create mode 100644 pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteDeptServiceFallbackImpl.java create mode 100644 pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/vo/UserInfoVO.java diff --git a/pig-common/pig-common-bom/pom.xml b/pig-common/pig-common-bom/pom.xml index 5377bc29..54cad8b5 100644 --- a/pig-common/pig-common-bom/pom.xml +++ b/pig-common/pig-common-bom/pom.xml @@ -40,6 +40,11 @@ pig-common-core ${pig.common.version} + + com.pig4cloud + pig-common-datascope + ${pig.common.version} + com.pig4cloud pig-common-datasource diff --git a/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/enums/DataScopeTypeEnum.java b/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/enums/DataScopeTypeEnum.java new file mode 100644 index 00000000..0ed6a969 --- /dev/null +++ b/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/enums/DataScopeTypeEnum.java @@ -0,0 +1,49 @@ +package com.pig4cloud.pig.common.core.constant.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 数据权限范围类型 + * @author hccake + */ +@Getter +@AllArgsConstructor +public enum DataScopeTypeEnum { + + /** + * 查询全部数据 + */ + ALL(0), + + /** + * 本人 + */ + SELF(1), + + /** + * 本人及子级 + */ + SELF_CHILD_LEVEL(2), + + /** + * 本级 + */ + LEVEL(3), + + /** + * 本级及子级 + */ + LEVEL_CHILD_LEVEL(4), + + /** + * 自定义 + */ + CUSTOM(5); + + /** + * 类型 + */ + private final Integer type; + +} diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigUserAuthenticationConverter.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigUserAuthenticationConverter.java index 725c25f1..ce09588a 100644 --- a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigUserAuthenticationConverter.java +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigUserAuthenticationConverter.java @@ -69,7 +69,8 @@ public class PigUserAuthenticationConverter implements UserAuthenticationConvert String username = (String) map.get(SecurityConstants.DETAILS_USERNAME); Integer id = (Integer) map.get(SecurityConstants.DETAILS_USER_ID); Integer deptId = (Integer) map.get(SecurityConstants.DETAILS_DEPT_ID); - PigUser user = new PigUser(id, deptId, username, N_A, true, true, true, true, authorities); + // TODO 数据权限获取 + PigUser user = new PigUser(id, deptId, username, N_A, true, true, true, true, authorities, null); return new UsernamePasswordAuthenticationToken(user, N_A, authorities); } return null; diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/datascope/DataScopeProcessor.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/datascope/DataScopeProcessor.java new file mode 100644 index 00000000..3f6d09ac --- /dev/null +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/datascope/DataScopeProcessor.java @@ -0,0 +1,21 @@ +package com.pig4cloud.pig.common.security.datascope; + +import com.pig4cloud.pig.admin.api.entity.SysRole; +import com.pig4cloud.pig.admin.api.entity.SysUser; + +import java.util.List; + +/** + * @author hccake + */ +public interface DataScopeProcessor { + + /** + * 根据用户和角色信息,合并用户最终的数据权限 + * @param user 用户 + * @param roles 角色列表 + * @return UserDataScope + */ + UserDataScope mergeScopeType(SysUser user, List roles); + +} diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/datascope/PigDataScopeProcessor.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/datascope/PigDataScopeProcessor.java new file mode 100644 index 00000000..08825dc5 --- /dev/null +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/datascope/PigDataScopeProcessor.java @@ -0,0 +1,119 @@ +package com.pig4cloud.pig.common.security.datascope; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pig.admin.api.entity.SysRole; +import com.pig4cloud.pig.admin.api.entity.SysUser; +import com.pig4cloud.pig.admin.api.feign.RemoteDeptService; +import com.pig4cloud.pig.admin.api.feign.RemoteUserService; +import com.pig4cloud.pig.common.core.constant.SecurityConstants; +import com.pig4cloud.pig.common.core.constant.enums.DataScopeTypeEnum; +import com.pig4cloud.pig.common.core.util.R; +import lombok.RequiredArgsConstructor; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author hccake + */ +@RequiredArgsConstructor +public class PigDataScopeProcessor implements DataScopeProcessor { + + private final RemoteDeptService remoteDeptService; + + private final RemoteUserService remoteUserService; + + /** + * 合并角色的数据权限类型,排除相同的权限后,大的权限覆盖小的 + * @param user 用户 + * @param roles 角色列表 + * @return List 合并后的权限 + */ + @Override + public UserDataScope mergeScopeType(SysUser user, List roles) { + UserDataScope userDataScope = new UserDataScope(); + Set scopeUserIds = userDataScope.getScopeUserIds(); + Set scopeDeptIds = userDataScope.getScopeDeptIds(); + + // 任何用户都应该可以看到自己的数据 + Integer userId = user.getUserId(); + scopeUserIds.add(userId); + + if (CollectionUtil.isEmpty(roles)) { + return userDataScope; + } + + // 根据角色的权限返回进行分组 + Map> map = roles.stream().collect(Collectors.groupingBy(SysRole::getScopeType)); + + // 如果有全部权限,直接返回 + if (map.containsKey(DataScopeTypeEnum.ALL.getType())) { + userDataScope.setAllScope(true); + return userDataScope; + } + + // 如果有本级及子级,删除其包含的几类数据权限 + boolean hasLevelChildLevel = map.containsKey(DataScopeTypeEnum.LEVEL_CHILD_LEVEL.getType()); + if (hasLevelChildLevel) { + map.remove(DataScopeTypeEnum.SELF.getType()); + map.remove(DataScopeTypeEnum.SELF_CHILD_LEVEL.getType()); + map.remove(DataScopeTypeEnum.LEVEL.getType()); + } + + // 是否有本人及子级权限 + boolean hasSelfChildLevel = map.containsKey(DataScopeTypeEnum.SELF_CHILD_LEVEL.getType()); + // 是否有本级权限 + boolean hasLevel = map.containsKey(DataScopeTypeEnum.LEVEL.getType()); + if (hasSelfChildLevel || hasLevel) { + // 如果有本人及子级或者本级,都删除本人的数据权限 + map.remove(DataScopeTypeEnum.SELF.getType()); + // 如果同时拥有,则等于本级及子级权限 + if (hasSelfChildLevel && hasLevel) { + map.remove(DataScopeTypeEnum.SELF_CHILD_LEVEL.getType()); + map.remove(DataScopeTypeEnum.LEVEL.getType()); + map.put(DataScopeTypeEnum.LEVEL_CHILD_LEVEL.getType(), new ArrayList<>()); + } + } + + // 这时如果仅仅只能看个人的,直接返回 + if (map.size() == 1 && map.containsKey(DataScopeTypeEnum.SELF.getType())) { + userDataScope.setOnlySelf(true); + return userDataScope; + } + + // 如果有 本级及子级 或者 本级,都把自己的 deptId 加进去 + Integer deptId = user.getDeptId(); + if (hasLevelChildLevel || hasLevel) { + scopeDeptIds.add(deptId); + } + // 如果有 本级及子级 或者 本人及子级,都把下级组织的 deptId 加进去 + if (hasLevelChildLevel || hasSelfChildLevel) { + List childDeptIdList = remoteDeptService.listChildDeptId(deptId, SecurityConstants.FROM_IN) + .getData(); + if (CollectionUtil.isNotEmpty(childDeptIdList)) { + scopeDeptIds.addAll(childDeptIdList); + } + } + // 自定义部门 + List sysRoles = map.get(DataScopeTypeEnum.CUSTOM.getType()); + if (CollectionUtil.isNotEmpty(sysRoles)) { + Set customDeptIds = sysRoles.stream().map(SysRole::getScopeResources).filter(Objects::nonNull) + .flatMap(x -> Arrays.stream(x.split(StrUtil.COMMA))).map(Integer::parseInt) + .collect(Collectors.toSet()); + scopeDeptIds.addAll(customDeptIds); + } + + // 把部门对应的用户id都放入集合中 + if (CollectionUtil.isNotEmpty(scopeDeptIds)) { + R> r = remoteUserService.listUserIdByDeptIds(scopeDeptIds, SecurityConstants.FROM_IN); + List userIds = r.getData(); + if (CollectionUtil.isNotEmpty(userIds)) { + scopeUserIds.addAll(userIds); + } + } + + return userDataScope; + } + +} diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/datascope/UserDataScope.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/datascope/UserDataScope.java new file mode 100644 index 00000000..98b333f6 --- /dev/null +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/datascope/UserDataScope.java @@ -0,0 +1,35 @@ +package com.pig4cloud.pig.common.security.datascope; + +import lombok.Data; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +/** + * @author hccake + */ +@Data +public class UserDataScope implements Serializable { + + /** + * 是否是全部数据权限 + */ + private boolean allScope = false; + + /** + * 是否仅能看自己 + */ + private boolean onlySelf = false; + + /** + * 数据权限范围,用户所能查看的用户id 集合 + */ + private Set scopeUserIds = new HashSet<>(); + + /** + * 数据权限范围,用户所能查看的部门id 集合 + */ + private Set scopeDeptIds = new HashSet<>(); + +} diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUser.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUser.java index ea635bfd..c3b9863f 100755 --- a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUser.java +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUser.java @@ -16,6 +16,7 @@ package com.pig4cloud.pig.common.security.service; +import com.pig4cloud.pig.common.security.datascope.UserDataScope; import lombok.Getter; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.core.GrantedAuthority; @@ -33,13 +34,19 @@ public class PigUser extends User { * 用户ID */ @Getter - private Integer id; + private final Integer id; /** * 部门ID */ @Getter - private Integer deptId; + private final Integer deptId; + + /** + * 用户数据权限信息 + */ + @Getter + private final UserDataScope userDataScope; /** * Construct the User with the details required by @@ -62,10 +69,11 @@ public class PigUser extends User { */ public PigUser(Integer id, Integer deptId, String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, - Collection authorities) { + Collection authorities, UserDataScope userDataScope) { super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); this.id = id; this.deptId = deptId; + this.userDataScope = userDataScope; } } diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java index 890324e3..442c8ac1 100755 --- a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java @@ -25,6 +25,8 @@ import com.pig4cloud.pig.common.core.constant.CacheConstants; import com.pig4cloud.pig.common.core.constant.CommonConstants; import com.pig4cloud.pig.common.core.constant.SecurityConstants; import com.pig4cloud.pig.common.core.util.R; +import com.pig4cloud.pig.common.security.datascope.DataScopeProcessor; +import com.pig4cloud.pig.common.security.datascope.UserDataScope; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -45,7 +47,7 @@ import java.util.Set; /** * 用户详细信息 * - * @author lengleng + * @author lengleng hccake */ @Slf4j @Service @@ -56,6 +58,8 @@ public class PigUserDetailsServiceImpl implements UserDetailsService { private final CacheManager cacheManager; + private final DataScopeProcessor dataScopeProcessor; + /** * 用户密码登录 * @param username 用户名 @@ -80,7 +84,7 @@ public class PigUserDetailsServiceImpl implements UserDetailsService { /** * 构建userdetails * @param result 用户信息 - * @return + * @return UserDetails */ private UserDetails getUserDetails(R result) { if (result == null || result.getData() == null) { @@ -100,10 +104,14 @@ public class PigUserDetailsServiceImpl implements UserDetailsService { .createAuthorityList(dbAuthsSet.toArray(new String[0])); SysUser user = info.getSysUser(); + // 数据权限填充 + UserDataScope userDataScope = dataScopeProcessor.mergeScopeType(user, info.getRoleList()); + // 构造security用户 return new PigUser(user.getUserId(), user.getDeptId(), user.getUsername(), SecurityConstants.BCRYPT + user.getPassword(), - StrUtil.equals(user.getLockFlag(), CommonConstants.STATUS_NORMAL), true, true, true, authorities); + StrUtil.equals(user.getLockFlag(), CommonConstants.STATUS_NORMAL), true, true, true, authorities, + userDataScope); } } diff --git a/pig-common/pig-common-security/src/main/resources/META-INF/spring.factories b/pig-common/pig-common-security/src/main/resources/META-INF/spring.factories index ba4694e7..42f2a723 100755 --- a/pig-common/pig-common-security/src/main/resources/META-INF/spring.factories +++ b/pig-common/pig-common-security/src/main/resources/META-INF/spring.factories @@ -1,4 +1,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.pig4cloud.pig.common.security.service.PigUserDetailsServiceImpl,\ - com.pig4cloud.pig.common.security.component.PigSecurityInnerAspect + com.pig4cloud.pig.common.security.component.PigSecurityInnerAspect,\ + com.pig4cloud.pig.common.security.datascope.PigDataScopeProcessor diff --git a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/dto/UserInfo.java b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/dto/UserInfo.java index 1c76397f..c466d27b 100644 --- a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/dto/UserInfo.java +++ b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/dto/UserInfo.java @@ -16,10 +16,14 @@ package com.pig4cloud.pig.admin.api.dto; +import com.pig4cloud.pig.admin.api.entity.SysMenu; +import com.pig4cloud.pig.admin.api.entity.SysRole; import com.pig4cloud.pig.admin.api.entity.SysUser; import lombok.Data; import java.io.Serializable; +import java.util.List; +import java.util.Set; /** * @author lengleng @@ -46,4 +50,9 @@ public class UserInfo implements Serializable { */ private Integer[] roles; + /** + * 角色集合 + */ + private List roleList; + } diff --git a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/entity/SysRole.java b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/entity/SysRole.java index 50b2c6d1..3d9a8fab 100644 --- a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/entity/SysRole.java +++ b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/entity/SysRole.java @@ -25,6 +25,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; /** *

@@ -56,6 +57,13 @@ public class SysRole extends BaseEntity { @ApiModelProperty(value = "角色描述") private String roleDesc; + @NotNull(message = "数据范围类型 不能为null") + @ApiModelProperty(value = "数据范围类型") + private Integer scopeType; + + @ApiModelProperty(value = "数据范围资源") + private String scopeResources; + /** * 删除标识(0-正常,1-删除) */ diff --git a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteDeptService.java b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteDeptService.java new file mode 100644 index 00000000..ab1eb527 --- /dev/null +++ b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteDeptService.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 pig4cloud Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.pig4cloud.pig.admin.api.feign; + +import com.pig4cloud.pig.admin.api.feign.factory.RemoteUserServiceFallbackFactory; +import com.pig4cloud.pig.common.core.constant.SecurityConstants; +import com.pig4cloud.pig.common.core.constant.ServiceNameConstants; +import com.pig4cloud.pig.common.core.util.R; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; + +import java.util.List; + +/** + * @author hccake + */ +@FeignClient(contextId = "remoteDeptService", value = ServiceNameConstants.UMPS_SERVICE, + fallbackFactory = RemoteUserServiceFallbackFactory.class) +public interface RemoteDeptService { + + /** + * 查收子级id列表 + * @return 返回子级id列表 + */ + @GetMapping("/child-id/{deptId}") + R> listChildDeptId(@PathVariable("deptId") Integer deptId, + @RequestHeader(SecurityConstants.FROM) String from); + +} diff --git a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteUserService.java b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteUserService.java index 30d5926e..eb00dece 100755 --- a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteUserService.java +++ b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteUserService.java @@ -25,6 +25,10 @@ import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; +import java.util.Set; /** * @author lengleng @@ -51,4 +55,14 @@ public interface RemoteUserService { @GetMapping("/social/info/{inStr}") R social(@PathVariable("inStr") String inStr); + /** + * 根据部门id,查询对应的用户 id 集合 + * @param deptIds 部门id 集合 + * @param from 调用标志 + * @return 用户 id 集合 + */ + @GetMapping("/user/ids") + R> listUserIdByDeptIds(@RequestParam("deptIds") Set deptIds, + @RequestHeader(SecurityConstants.FROM) String from); + } diff --git a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/factory/RemoteDeptServiceFallbackFactory.java b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/factory/RemoteDeptServiceFallbackFactory.java new file mode 100644 index 00000000..14ab4c78 --- /dev/null +++ b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/factory/RemoteDeptServiceFallbackFactory.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 pig4cloud Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.pig4cloud.pig.admin.api.feign.factory; + +import com.pig4cloud.pig.admin.api.feign.RemoteDeptService; +import com.pig4cloud.pig.admin.api.feign.fallback.RemoteDeptServiceFallbackImpl; +import org.springframework.cloud.openfeign.FallbackFactory; +import org.springframework.stereotype.Component; + +/** + * @author hccake + */ +@Component +public class RemoteDeptServiceFallbackFactory implements FallbackFactory { + + @Override + public RemoteDeptService create(Throwable throwable) { + RemoteDeptServiceFallbackImpl remoteDeptServiceFallback = new RemoteDeptServiceFallbackImpl(); + remoteDeptServiceFallback.setCause(throwable); + return remoteDeptServiceFallback; + } + +} diff --git a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteDeptServiceFallbackImpl.java b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteDeptServiceFallbackImpl.java new file mode 100644 index 00000000..bed2d8cd --- /dev/null +++ b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteDeptServiceFallbackImpl.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 pig4cloud Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.pig4cloud.pig.admin.api.feign.fallback; + +import com.pig4cloud.pig.admin.api.dto.UserInfo; +import com.pig4cloud.pig.admin.api.feign.RemoteDeptService; +import com.pig4cloud.pig.admin.api.feign.RemoteUserService; +import com.pig4cloud.pig.common.core.util.R; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author hccake + */ +@Slf4j +@Component +public class RemoteDeptServiceFallbackImpl implements RemoteDeptService { + + @Setter + private Throwable cause; + + @Override + public R> listChildDeptId(Integer deptId, String from) { + log.error("[listChildDeptId] feign 查询子级部门id列表失败", cause); + return null; + } + +} diff --git a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java index db12847b..389a6dd5 100755 --- a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java +++ b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java @@ -23,6 +23,9 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import java.util.List; +import java.util.Set; + /** * @author lengleng * @date 2019/2/1 @@ -57,4 +60,10 @@ public class RemoteUserServiceFallbackImpl implements RemoteUserService { return null; } + @Override + public R> listUserIdByDeptIds(Set deptIds, String from) { + log.error("feign 根据部门ids查询用户Id集合失败:{}", deptIds, cause); + return null; + } + } diff --git a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/vo/UserInfoVO.java b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/vo/UserInfoVO.java new file mode 100644 index 00000000..ab1451ce --- /dev/null +++ b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/vo/UserInfoVO.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 pig4cloud Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.pig4cloud.pig.admin.api.vo; + +import com.pig4cloud.pig.admin.api.entity.SysUser; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author lengleng + * @date 2019/2/1 + *

+ * commit('SET_ROLES', data) commit('SET_NAME', data) commit('SET_AVATAR', data) + * commit('SET_INTRODUCTION', data) commit('SET_PERMISSIONS', data) + */ +@Data +public class UserInfoVO implements Serializable { + + /** + * 用户基本信息 + */ + private SysUser sysUser; + + /** + * 权限标识集合 + */ + private String[] permissions; + + /** + * 角色集合 + */ + private Integer[] roles; + +} diff --git a/pig-upms/pig-upms-biz/pom.xml b/pig-upms/pig-upms-biz/pom.xml index 74f22d87..b4d967c0 100644 --- a/pig-upms/pig-upms-biz/pom.xml +++ b/pig-upms/pig-upms-biz/pom.xml @@ -55,6 +55,11 @@ com.pig4cloud pig-common-mybatis + + + com.pig4cloud + pig-common-datascope + com.alibaba.cloud diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/DeptController.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/DeptController.java index e56bc548..9dd62e37 100644 --- a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/DeptController.java +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/DeptController.java @@ -20,6 +20,7 @@ import com.pig4cloud.pig.admin.api.entity.SysDept; import com.pig4cloud.pig.admin.service.SysDeptService; import com.pig4cloud.pig.common.core.util.R; import com.pig4cloud.pig.common.log.annotation.SysLog; +import com.pig4cloud.pig.common.security.annotation.Inner; import io.swagger.annotations.Api; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -27,6 +28,7 @@ import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.time.LocalDateTime; +import java.util.List; /** *

@@ -121,4 +123,14 @@ public class DeptController { return R.ok(sysDeptService.getOne(new QueryWrapper<>(condition))); } + /** + * 查收子级id列表 + * @return 返回子级id列表 + */ + @Inner + @GetMapping(value = "/child-id/{deptId}") + public R> listChildDeptId(@PathVariable Integer deptId) { + return R.ok(sysDeptService.listChildDeptId(deptId)); + } + } diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/UserController.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/UserController.java index 8fd8fd32..ae191416 100644 --- a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/UserController.java +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/UserController.java @@ -20,8 +20,10 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.pig4cloud.pig.admin.api.dto.UserDTO; +import com.pig4cloud.pig.admin.api.dto.UserInfo; import com.pig4cloud.pig.admin.api.entity.SysUser; import com.pig4cloud.pig.admin.api.vo.UserExcelVO; +import com.pig4cloud.pig.admin.api.vo.UserInfoVO; import com.pig4cloud.pig.admin.service.SysUserService; import com.pig4cloud.pig.common.core.util.R; import com.pig4cloud.pig.common.log.annotation.SysLog; @@ -33,10 +35,19 @@ import io.swagger.annotations.Api; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.util.List; +import java.util.Set; /** * @author lengleng @@ -61,7 +72,12 @@ public class UserController { if (user == null) { return R.failed("获取当前用户信息失败"); } - return R.ok(userService.getUserInfo(user)); + UserInfo userInfo = userService.getUserInfo(user); + UserInfoVO vo = new UserInfoVO(); + vo.setSysUser(userInfo.getSysUser()); + vo.setRoles(userInfo.getRoles()); + vo.setPermissions(userInfo.getPermissions()); + return R.ok(vo); } /** @@ -78,6 +94,17 @@ public class UserController { return R.ok(userService.getUserInfo(user)); } + /** + * 根据部门id,查询对应的用户 id 集合 + * @param deptIds 部门id 集合 + * @return 用户 id 集合 + */ + @Inner + @GetMapping("/ids") + public R> listUserIdByDeptIds(@RequestParam("deptIds") Set deptIds) { + return R.ok(userService.listUserIdByDeptIds(deptIds)); + } + /** * 通过ID查询用户信息 * @param id ID diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/SysDeptService.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/SysDeptService.java index 55f5e543..8329e9b9 100644 --- a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/SysDeptService.java +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/SysDeptService.java @@ -65,4 +65,11 @@ public interface SysDeptService extends IService { */ Boolean updateDeptById(SysDept sysDept); + /** + * 查找指定部门的子部门id列表 + * @param deptId 部门id + * @return List + */ + List listChildDeptId(Integer deptId); + } diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/SysUserService.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/SysUserService.java index f03d0b3a..799c0c80 100644 --- a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/SysUserService.java +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/SysUserService.java @@ -28,6 +28,7 @@ import com.pig4cloud.pig.common.core.util.R; import org.springframework.validation.BindingResult; import java.util.List; +import java.util.Set; /** * @author lengleng @@ -107,4 +108,11 @@ public interface SysUserService extends IService { */ R importUser(List excelVOList, BindingResult bindingResult); + /** + * 根据部门 id 列表查询对应的用户 id 集合 + * @param deptIds 部门 id 列表 + * @return userIdList + */ + List listUserIdByDeptIds(Set deptIds); + } diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/impl/SysDeptServiceImpl.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/impl/SysDeptServiceImpl.java index afc809f2..505629d3 100644 --- a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/impl/SysDeptServiceImpl.java +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/impl/SysDeptServiceImpl.java @@ -33,6 +33,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -108,6 +109,16 @@ public class SysDeptServiceImpl extends ServiceImpl impl return Boolean.TRUE; } + @Override + public List listChildDeptId(Integer deptId) { + List deptRelations = sysDeptRelationService + .list(Wrappers.lambdaQuery().eq(SysDeptRelation::getAncestor, deptId)); + if (CollUtil.isNotEmpty(deptRelations)) { + return deptRelations.stream().map(SysDeptRelation::getDescendant).collect(Collectors.toList()); + } + return new ArrayList<>(); + } + /** * 查询全部部门树 * @return 树 diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/impl/SysUserServiceImpl.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/impl/SysUserServiceImpl.java index a8327551..b7116aac 100644 --- a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/impl/SysUserServiceImpl.java +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/impl/SysUserServiceImpl.java @@ -25,7 +25,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.pig4cloud.pig.admin.api.dto.UserDTO; import com.pig4cloud.pig.admin.api.dto.UserInfo; -import com.pig4cloud.pig.admin.api.entity.*; +import com.pig4cloud.pig.admin.api.entity.SysDept; +import com.pig4cloud.pig.admin.api.entity.SysMenu; +import com.pig4cloud.pig.admin.api.entity.SysRole; +import com.pig4cloud.pig.admin.api.entity.SysUser; +import com.pig4cloud.pig.admin.api.entity.SysUserRole; import com.pig4cloud.pig.admin.api.vo.UserExcelVO; import com.pig4cloud.pig.admin.api.vo.UserVO; import com.pig4cloud.pig.admin.mapper.SysDeptMapper; @@ -107,9 +111,11 @@ public class SysUserServiceImpl extends ServiceImpl impl public UserInfo getUserInfo(SysUser sysUser) { UserInfo userInfo = new UserInfo(); userInfo.setSysUser(sysUser); + // 设置角色列表 + List roleList = sysRoleMapper.listRolesByUserId(sysUser.getUserId()); + userInfo.setRoleList(roleList); // 设置角色列表 (ID) - List roleIds = sysRoleMapper.listRolesByUserId(sysUser.getUserId()).stream().map(SysRole::getRoleId) - .collect(Collectors.toList()); + List roleIds = roleList.stream().map(SysRole::getRoleId).collect(Collectors.toList()); userInfo.setRoles(ArrayUtil.toArray(roleIds, Integer.class)); // 设置权限列表(menu.permission) Set permissions = sysMenuService.findMenuByRoleId(CollUtil.join(roleIds, StrUtil.COMMA)).stream() @@ -117,6 +123,7 @@ public class SysUserServiceImpl extends ServiceImpl impl .filter(m -> StrUtil.isNotBlank(m.getPermission())).map(SysMenu::getPermission) .collect(Collectors.toSet()); userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class)); + return userInfo; } @@ -295,6 +302,13 @@ public class SysUserServiceImpl extends ServiceImpl impl return R.ok(); } + @Override + public List listUserIdByDeptIds(Set deptIds) { + return this.listObjs( + Wrappers.lambdaQuery(SysUser.class).select(SysUser::getUserId).in(SysUser::getDeptId, deptIds), + Integer.class::cast); + } + /** * 插入excel User */ From 637983ecf94f037451b097adac89a6d3ecda4d15 Mon Sep 17 00:00:00 2001 From: Hccake Date: Sun, 12 Sep 2021 00:00:31 +0800 Subject: [PATCH 04/16] =?UTF-8?q?:zap:=20=E6=B7=BB=E5=8A=A0=20sys=5Fuser?= =?UTF-8?q?=20=E8=A1=A8=E7=9A=84=20DataScope=20=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/AuthorizationServerConfig.java | 17 ++- .../converter/CustomAccessTokenConverter.java | 37 ++++++ .../core/constant/SecurityConstants.java | 5 + .../PigUserAuthenticationConverter.java | 17 ++- .../admin/api/feign/RemoteDeptService.java | 6 +- .../main/resources/META-INF/spring.factories | 4 +- .../pig/admin/datascope/PigDataScope.java | 115 ++++++++++++++++++ .../service/impl/SysDeptServiceImpl.java | 4 +- 8 files changed, 192 insertions(+), 13 deletions(-) create mode 100644 pig-auth/src/main/java/com/pig4cloud/pig/auth/converter/CustomAccessTokenConverter.java create mode 100644 pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/datascope/PigDataScope.java diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfig.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfig.java index 72563a4f..17b36f1b 100755 --- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfig.java +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfig.java @@ -16,6 +16,7 @@ package com.pig4cloud.pig.auth.config; +import com.pig4cloud.pig.auth.converter.CustomAccessTokenConverter; import com.pig4cloud.pig.common.core.constant.CacheConstants; import com.pig4cloud.pig.common.core.constant.SecurityConstants; import com.pig4cloud.pig.common.security.component.PigWebResponseExceptionTranslator; @@ -63,10 +64,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap @Override @SneakyThrows public void configure(ClientDetailsServiceConfigurer clients) { - PigClientDetailsService clientDetailsService = new PigClientDetailsService(dataSource); - clientDetailsService.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT); - clientDetailsService.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT); - clients.withClientDetails(clientDetailsService); + clients.withClientDetails(pigClientDetailsService()); } @Override @@ -80,7 +78,8 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap .tokenEnhancer(tokenEnhancer()).userDetailsService(userDetailsService) .authenticationManager(authenticationManager).reuseRefreshTokens(false) .pathMapping("/oauth/confirm_access", "/token/confirm_access") - .exceptionTranslator(new PigWebResponseExceptionTranslator()); + .exceptionTranslator(new PigWebResponseExceptionTranslator()) + .accessTokenConverter(new CustomAccessTokenConverter(pigClientDetailsService())); } @Bean @@ -104,4 +103,12 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap }; } + @Bean + public PigClientDetailsService pigClientDetailsService() { + PigClientDetailsService clientDetailsService = new PigClientDetailsService(dataSource); + clientDetailsService.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT); + clientDetailsService.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT); + return clientDetailsService; + } + } diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/converter/CustomAccessTokenConverter.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/converter/CustomAccessTokenConverter.java new file mode 100644 index 00000000..e35dc594 --- /dev/null +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/converter/CustomAccessTokenConverter.java @@ -0,0 +1,37 @@ +package com.pig4cloud.pig.auth.converter; + +import com.pig4cloud.pig.common.core.constant.SecurityConstants; +import com.pig4cloud.pig.common.security.service.PigClientDetailsService; +import com.pig4cloud.pig.common.security.service.PigUser; +import lombok.RequiredArgsConstructor; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.ClientDetails; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter; + +import java.util.Map; + +/** + * @author hccake + */ +@RequiredArgsConstructor +public class CustomAccessTokenConverter extends DefaultAccessTokenConverter { + + final PigClientDetailsService pigClientDetailsService; + + @Override + @SuppressWarnings("unchecked") + public Map convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) { + Map response = (Map) super.convertAccessToken(token, authentication); + + ClientDetails clientDetails = pigClientDetailsService + .loadClientByClientId(authentication.getOAuth2Request().getClientId()); + if (clientDetails != null && clientDetails.getScope().contains("read_data_scope")) { + PigUser principal = (PigUser) authentication.getPrincipal(); + response.put(SecurityConstants.DETAILS_USER_DATA_SCOPE, principal.getUserDataScope()); + } + + return response; + } + +} diff --git a/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/SecurityConstants.java b/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/SecurityConstants.java index c51aab5b..8cf51a60 100755 --- a/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/SecurityConstants.java +++ b/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/SecurityConstants.java @@ -109,6 +109,11 @@ public interface SecurityConstants { */ String DETAILS_LICENSE = "license"; + /** + * 用户数据权限信息 + */ + String DETAILS_USER_DATA_SCOPE = "user_data_scope"; + /** * 验证码有效期,默认 60秒 */ diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigUserAuthenticationConverter.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigUserAuthenticationConverter.java index ce09588a..e880d48d 100644 --- a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigUserAuthenticationConverter.java +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigUserAuthenticationConverter.java @@ -17,6 +17,7 @@ package com.pig4cloud.pig.common.security.component; import com.pig4cloud.pig.common.core.constant.SecurityConstants; +import com.pig4cloud.pig.common.security.datascope.UserDataScope; import com.pig4cloud.pig.common.security.service.PigUser; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -26,8 +27,11 @@ import org.springframework.security.oauth2.provider.token.UserAuthenticationConv import org.springframework.util.StringUtils; import java.util.Collection; +import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.Set; /** * @author lengleng @@ -69,8 +73,17 @@ public class PigUserAuthenticationConverter implements UserAuthenticationConvert String username = (String) map.get(SecurityConstants.DETAILS_USERNAME); Integer id = (Integer) map.get(SecurityConstants.DETAILS_USER_ID); Integer deptId = (Integer) map.get(SecurityConstants.DETAILS_DEPT_ID); - // TODO 数据权限获取 - PigUser user = new PigUser(id, deptId, username, N_A, true, true, true, true, authorities, null); + + UserDataScope userDataScope = new UserDataScope(); + Object value = map.get(SecurityConstants.DETAILS_USER_DATA_SCOPE); + if (value != null) { + Map userDataScopeMap = (Map) value; + userDataScope.setAllScope((boolean) userDataScopeMap.get("allScope")); + userDataScope.setOnlySelf((boolean) userDataScopeMap.get("onlySelf")); + userDataScope.setScopeUserIds(new HashSet<>((List) userDataScopeMap.get("scopeUserIds"))); + userDataScope.setScopeDeptIds(new HashSet<>((List) userDataScopeMap.get("scopeDeptIds"))); + } + PigUser user = new PigUser(id, deptId, username, N_A, true, true, true, true, authorities, userDataScope); return new UsernamePasswordAuthenticationToken(user, N_A, authorities); } return null; diff --git a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteDeptService.java b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteDeptService.java index ab1eb527..12f91bf0 100644 --- a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteDeptService.java +++ b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteDeptService.java @@ -16,7 +16,7 @@ package com.pig4cloud.pig.admin.api.feign; -import com.pig4cloud.pig.admin.api.feign.factory.RemoteUserServiceFallbackFactory; +import com.pig4cloud.pig.admin.api.feign.factory.RemoteDeptServiceFallbackFactory; import com.pig4cloud.pig.common.core.constant.SecurityConstants; import com.pig4cloud.pig.common.core.constant.ServiceNameConstants; import com.pig4cloud.pig.common.core.util.R; @@ -31,14 +31,14 @@ import java.util.List; * @author hccake */ @FeignClient(contextId = "remoteDeptService", value = ServiceNameConstants.UMPS_SERVICE, - fallbackFactory = RemoteUserServiceFallbackFactory.class) + fallbackFactory = RemoteDeptServiceFallbackFactory.class) public interface RemoteDeptService { /** * 查收子级id列表 * @return 返回子级id列表 */ - @GetMapping("/child-id/{deptId}") + @GetMapping("/dept/child-id/{deptId}") R> listChildDeptId(@PathVariable("deptId") Integer deptId, @RequestHeader(SecurityConstants.FROM) String from); diff --git a/pig-upms/pig-upms-api/src/main/resources/META-INF/spring.factories b/pig-upms/pig-upms-api/src/main/resources/META-INF/spring.factories index 8ed59881..a948b89e 100755 --- a/pig-upms/pig-upms-api/src/main/resources/META-INF/spring.factories +++ b/pig-upms/pig-upms-api/src/main/resources/META-INF/spring.factories @@ -2,6 +2,8 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.pig4cloud.pig.admin.api.feign.fallback.RemoteUserServiceFallbackImpl,\ com.pig4cloud.pig.admin.api.feign.fallback.RemoteLogServiceFallbackImpl,\ com.pig4cloud.pig.admin.api.feign.fallback.RemoteTokenServiceFallbackImpl,\ + com.pig4cloud.pig.admin.api.feign.fallback.RemoteDeptServiceFallbackImpl,\ com.pig4cloud.pig.admin.api.feign.factory.RemoteUserServiceFallbackFactory,\ com.pig4cloud.pig.admin.api.feign.factory.RemoteLogServiceFallbackFactory,\ - com.pig4cloud.pig.admin.api.feign.factory.RemoteTokenServiceFallbackFactory + com.pig4cloud.pig.admin.api.feign.factory.RemoteTokenServiceFallbackFactory,\ + com.pig4cloud.pig.admin.api.feign.factory.RemoteDeptServiceFallbackFactory diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/datascope/PigDataScope.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/datascope/PigDataScope.java new file mode 100644 index 00000000..93da1ae9 --- /dev/null +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/datascope/PigDataScope.java @@ -0,0 +1,115 @@ +package com.pig4cloud.pig.admin.datascope; + +import cn.hutool.core.collection.CollectionUtil; +import com.pig4cloud.pig.common.security.datascope.UserDataScope; +import com.pig4cloud.pig.common.security.service.PigUser; +import com.pig4cloud.pig.common.security.util.SecurityUtils; +import com.pigcloud.pig.common.datascope.DataScope; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.Parenthesis; +import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.InExpression; +import net.sf.jsqlparser.schema.Column; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; + +/** + * 数据权限控制,要求表至少有个 user_id 字段 + * + * @author hccake + */ +@Component +public class PigDataScope implements DataScope { + + private static final String USER_ID = "user_id"; + + private static final String DEPT_ID = "dept_id"; + + /** + * 拥有 dept_id 字段的表名集合 + */ + private static final Set DEPT_ID_TABLE_NAMES = CollectionUtil.newHashSet("sys_user"); + + /** + * 仅拥有 user_id 字段的表名集合 + */ + private static final Set USER_ID_TABLE_NAMES = CollectionUtil.newHashSet(); + + private final Set tableNames; + + public PigDataScope() { + Set set = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + set.addAll(DEPT_ID_TABLE_NAMES); + set.addAll(USER_ID_TABLE_NAMES); + this.tableNames = Collections.unmodifiableSet(set); + } + + @Override + public String getResource() { + return "userData"; + } + + @Override + public Collection getTableNames() { + return this.tableNames; + } + + @Override + public Expression getExpression(String tableName, Alias tableAlias) { + // 获取当前登录用户 + PigUser user = SecurityUtils.getUser(); + if (user == null) { + return null; + } + + UserDataScope userDataScope = user.getUserDataScope(); + + // 如果数据权限是全部,直接放行 + if (userDataScope.isAllScope()) { + return null; + } + + // 如果数据权限是仅自己 + if (userDataScope.isOnlySelf()) { + // 数据权限规则,where user_id = xx + return userIdEqualsToExpression(tableAlias, user.getId()); + } + + // 如果当前表有部门字段,则优先使用部门字段控制范围 + if (DEPT_ID_TABLE_NAMES.contains(tableName)) { + // 数据权限规则,where (user_id =xx or dept_id in ("x","y")) + EqualsTo equalsTo = userIdEqualsToExpression(tableAlias, user.getId()); + Expression inExpression = getInExpression(tableAlias, DEPT_ID, userDataScope.getScopeDeptIds()); + // 这里一定要加括号,否则如果有其他查询条件,or 会出问题 + return new Parenthesis(new OrExpression(equalsTo, inExpression)); + } + else { + // 数据权限规则,where user_id in ("x","y") + return getInExpression(tableAlias, USER_ID, userDataScope.getScopeUserIds()); + } + } + + private EqualsTo userIdEqualsToExpression(Alias tableAlias, Integer userId) { + Column column = new Column(tableAlias == null ? USER_ID : tableAlias.getName() + "." + USER_ID); + return new EqualsTo(column, new LongValue(userId)); + } + + private Expression getInExpression(Alias tableAlias, String columnName, Set scopeUserIds) { + Column column = new Column(tableAlias == null ? columnName : tableAlias.getName() + "." + columnName); + ExpressionList expressionList = new ExpressionList(); + List list = scopeUserIds.stream().map(LongValue::new).collect(Collectors.toList()); + expressionList.setExpressions(list); + return new InExpression(column, expressionList); + } + +} diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/impl/SysDeptServiceImpl.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/impl/SysDeptServiceImpl.java index 505629d3..3b69aab4 100644 --- a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/impl/SysDeptServiceImpl.java +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/impl/SysDeptServiceImpl.java @@ -111,8 +111,8 @@ public class SysDeptServiceImpl extends ServiceImpl impl @Override public List listChildDeptId(Integer deptId) { - List deptRelations = sysDeptRelationService - .list(Wrappers.lambdaQuery().eq(SysDeptRelation::getAncestor, deptId)); + List deptRelations = sysDeptRelationService.list(Wrappers.lambdaQuery() + .eq(SysDeptRelation::getAncestor, deptId).ne(SysDeptRelation::getDescendant, deptId)); if (CollUtil.isNotEmpty(deptRelations)) { return deptRelations.stream().map(SysDeptRelation::getDescendant).collect(Collectors.toList()); } From e6eccedead514f86c1939ac51dd4e1f007286d8e Mon Sep 17 00:00:00 2001 From: Hccake Date: Sun, 12 Sep 2021 00:08:45 +0800 Subject: [PATCH 05/16] =?UTF-8?q?:arrow=5Fup:=20=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=20v3.3.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pig-common/pig-common-datascope/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pig-common/pig-common-datascope/pom.xml b/pig-common/pig-common-datascope/pom.xml index 1a22953e..df6236b7 100644 --- a/pig-common/pig-common-datascope/pom.xml +++ b/pig-common/pig-common-datascope/pom.xml @@ -5,7 +5,7 @@ pig-common com.pig4cloud - 3.3.3 + 3.3.4 4.0.0 From 4e6d9d719b8eaa55d7a5b113aae2b70d3a7e25b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=91=E5=BD=A9ing?= <382170522@qq.com> Date: Sun, 12 Sep 2021 07:37:19 +0800 Subject: [PATCH 06/16] =?UTF-8?q?:whale:=20Work=20about=20Docker.=20?= =?UTF-8?q?=E7=AE=80=E5=8C=96nacos=20=E9=95=9C=E5=83=8F=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pig-register/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pig-register/Dockerfile b/pig-register/Dockerfile index 5d3bba5a..f989b9bd 100755 --- a/pig-register/Dockerfile +++ b/pig-register/Dockerfile @@ -6,7 +6,7 @@ RUN java -Djarmode=layertools -jar app.jar extract && rm app.jar FROM moxm/java:1.8-full LABEL maintainer="jclazz@outlook.com" -RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && apk --no-cache add libstdc++ + ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" WORKDIR pig-register @@ -17,4 +17,4 @@ COPY --from=builder /build/application/ ./ EXPOSE 8848 -CMD sleep 30; java $JAVA_OPTS org.springframework.boot.loader.JarLauncher \ No newline at end of file +CMD sleep 30; java $JAVA_OPTS org.springframework.boot.loader.JarLauncher From 6f5473ef4d7059484fb24123e09d21a61634a954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=91=E5=BD=A9ing?= <382170522@qq.com> Date: Sun, 12 Sep 2021 07:37:47 +0800 Subject: [PATCH 07/16] =?UTF-8?q?:green=5Fheart:=20Fixing=20CI=20Build.=20?= =?UTF-8?q?fork=20=E4=BB=93=E5=BA=93=E4=B8=8D=E6=89=A7=E8=A1=8C=E9=92=89?= =?UTF-8?q?=E9=92=89=20action=E7=BB=93=E6=9E=9C=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/maven.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 6a5d8875..a79a737c 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -27,7 +27,7 @@ jobs: run: mvn spring-javaformat:validate - name: success - if: ${{ success() }} + if: success() && github.repository == 'pig-mesh/pig' uses: fifsky/dingtalk-action@master with: url: ${{ secrets.DINGTALK_WEBHOOK}} @@ -38,7 +38,7 @@ jobs: > ^_^ from github action message - name: failure - if: ${{ failure() }} + if: failure() && github.repository == 'pig-mesh/pig' uses: fifsky/dingtalk-action@master with: url: ${{ secrets.DINGTALK_WEBHOOK}} From 828d4e156d2a7dc46361e766d079e9f7e397a138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=91=E5=BD=A9ing?= <382170522@qq.com> Date: Sun, 12 Sep 2021 07:49:15 +0800 Subject: [PATCH 08/16] =?UTF-8?q?:green=5Fheart:=20Fixing=20CI=20Build.=20?= =?UTF-8?q?github=20action=E7=BB=93=E6=9E=9C=E6=8E=A8=E9=80=81=E5=88=B0=20?= =?UTF-8?q?=E4=BC=81=E5=BE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/maven.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index a79a737c..d8faa160 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -28,10 +28,11 @@ jobs: - name: success if: success() && github.repository == 'pig-mesh/pig' - uses: fifsky/dingtalk-action@master + uses: chf007/action-wechat-work@master + env: + WECHAT_WORK_BOT_WEBHOOK: ${{secrets.WECHAT_WORK_BOT_WEBHOOK}} with: - url: ${{ secrets.DINGTALK_WEBHOOK}} - type: markdown + msgtype: markdown content: | # 💯👨‍💻 Success 🎉🎉🎉 > Github Action: https://github.com/pig-mesh/pig success @@ -39,10 +40,11 @@ jobs: - name: failure if: failure() && github.repository == 'pig-mesh/pig' - uses: fifsky/dingtalk-action@master + uses: chf007/action-wechat-work@master + env: + WECHAT_WORK_BOT_WEBHOOK: ${{secrets.WECHAT_WORK_BOT_WEBHOOK}} with: - url: ${{ secrets.DINGTALK_WEBHOOK}} - type: markdown + msgtype: markdown content: | # 💤🤷‍♀️ failure 🙅‍♂️💣 > Github Action: https://github.com/pig-mesh/pig failure From 389ce535ad3d6a84a44c15e8ac6ff2ad584c5fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=91=86=E6=B8=A1?= Date: Sun, 12 Sep 2021 09:23:49 +0000 Subject: [PATCH 09/16] =?UTF-8?q?update=20db/pig=5Fconfig.sql.=20=E5=92=8C?= =?UTF-8?q?oos=20spring-boot-starter-1.0.1.jar=E4=B8=8D=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/pig_config.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/pig_config.sql b/db/pig_config.sql index 3a98c92c..723135c1 100644 --- a/db/pig_config.sql +++ b/db/pig_config.sql @@ -41,7 +41,7 @@ INSERT INTO `config_info` VALUES (2, 'pig-auth-dev.yml', 'DEFAULT_GROUP', '# 数 INSERT INTO `config_info` VALUES (3, 'pig-codegen-dev.yml', 'DEFAULT_GROUP', '## spring security 配置\nsecurity:\n oauth2:\n client:\n client-id: ENC(27v1agvAug87ANOVnbKdsw==)\n client-secret: ENC(VbnkopxrwgbFVKp+UxJ2pg==)\n scope: server\n\n# 数据源配置\nspring:\n datasource:\n type: com.zaxxer.hikari.HikariDataSource\n driver-class-name: com.mysql.cj.jdbc.Driver\n username: root\n password: root\n url: jdbc:mysql://pig-mysql:3306/pig_codegen?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai\n resources:\n static-locations: classpath:/static/,classpath:/views/\n\n# 直接放行URL\nignore:\n urls:\n - /v2/api-docs\n - /actuator/**\n', 'abc702838b34d11b46e96143ccd9f367', '2019-11-29 16:32:12', '2019-11-29 16:32:12', NULL, '127.0.0.1', '', '', '代码生成配置', NULL, NULL, 'yaml', NULL); INSERT INTO `config_info` VALUES (4, 'pig-gateway-dev.yml', 'DEFAULT_GROUP', 'spring:\n cloud:\n gateway:\n locator:\n enabled: true\n routes:\n # 认证中心\n - id: pig-auth\n uri: lb://pig-auth\n predicates:\n - Path=/auth/**\n filters:\n # 验证码处理\n - ValidateCodeGatewayFilter\n # 前端密码解密\n - PasswordDecoderFilter\n #UPMS 模块\n - id: pig-upms-biz\n uri: lb://pig-upms-biz\n predicates:\n - Path=/admin/**\n filters:\n # 限流配置\n - name: RequestRateLimiter\n args:\n key-resolver: \'#{@remoteAddrKeyResolver}\'\n redis-rate-limiter.replenishRate: 100\n redis-rate-limiter.burstCapacity: 200\n # 代码生成模块\n - id: pig-codegen\n uri: lb://pig-codegen\n predicates:\n - Path=/gen/**\n\n\ngateway:\n encode-key: \'thanks,pig4cloud\'\n ignore-clients:\n - test\n\nswagger:\n ignore-providers:\n - pig-auth\n - pig-codegen\n', '5cd71b235930c78e700819b944a14446', '2019-11-29 16:32:42', '2020-10-09 17:10:45', NULL, '0:0:0:0:0:0:0:1', '', '', '网关配置', '', '', 'yaml', ''); INSERT INTO `config_info` VALUES (5, 'pig-monitor-dev.yml', 'DEFAULT_GROUP', 'spring:\n # 安全配置\n security:\n user:\n name: ENC(8Hk2ILNJM8UTOuW/Xi75qg==) # pig\n password: ENC(o6cuPFfUevmTbkmBnE67Ow====) # pig\n', '85509c6f8c67c364dc78301896274f26', '2019-11-29 16:33:05', '2019-11-29 16:33:05', NULL, '127.0.0.1', '', '', '监控配置', NULL, NULL, 'yaml', NULL); -INSERT INTO `config_info` VALUES (6, 'pig-upms-biz-dev.yml', 'DEFAULT_GROUP', 'security:\n oauth2:\n client:\n client-id: ENC(imENTO7M8bLO38LFSIxnzw==)\n client-secret: ENC(i3cDFhs26sa2Ucrfz2hnQw==)\n scope: server\n\n# 数据源\nspring:\n datasource:\n type: com.zaxxer.hikari.HikariDataSource\n driver-class-name: com.mysql.cj.jdbc.Driver\n username: root\n password: root\n url: jdbc:mysql://pig-mysql:3306/pig?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai\n\n# 文件上传相关 支持阿里云、华为云、腾讯、minio\noss:\n endpoint: https://play.min.io:9000\n access-key: Q3AM3UQ867SPQQA43P2F\n secret-key: zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG\n bucket-name: test-oss', '5041ac486e18aa0dd0bf624bb83806de', '2019-11-29 16:52:32', '2021-09-11 14:19:55', '', '127.0.0.1', '', '', '统一权限', 'null', 'null', 'yaml', 'null'); +INSERT INTO `config_info` VALUES (6, 'pig-upms-biz-dev.yml', 'DEFAULT_GROUP', 'security:\n oauth2:\n client:\n client-id: ENC(imENTO7M8bLO38LFSIxnzw==)\n client-secret: ENC(i3cDFhs26sa2Ucrfz2hnQw==)\n scope: server\n\n# 数据源\nspring:\n datasource:\n type: com.zaxxer.hikari.HikariDataSource\n driver-class-name: com.mysql.cj.jdbc.Driver\n username: root\n password: root\n url: jdbc:mysql://pig-mysql:3306/pig?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai\n\n# 文件上传相关 支持阿里云、华为云、腾讯、minio\noss:\n endpoint: https://play.min.io:9000\n accessKey: Q3AM3UQ867SPQQA43P2F\n secretKey: zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG\n bucket-name: test-oss', '5041ac486e18aa0dd0bf624bb83806de', '2019-11-29 16:52:32', '2021-09-11 14:19:55', '', '127.0.0.1', '', '', '统一权限', 'null', 'null', 'yaml', 'null'); COMMIT; -- ---------------------------- From 86cae4e0ca25c249067696b781acaeb6d501b1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=91=E5=BD=A9ing?= <382170522@qq.com> Date: Sun, 12 Sep 2021 07:53:23 +0800 Subject: [PATCH 10/16] =?UTF-8?q?:green=5Fheart:=20Fixing=20CI=20Build.=20?= =?UTF-8?q?github=20action=E7=BB=93=E6=9E=9C=E6=8E=A8=E9=80=81=E5=88=B0=20?= =?UTF-8?q?=E4=BC=81=E5=BE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :green_heart: Fixing CI Build. --- .github/workflows/maven.yml | 78 ++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index d8faa160..79e2a38a 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -13,39 +13,53 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v2 - with: - java-version: '11' - distribution: 'adopt' + - uses: shaowenchen/debugger-action@v2 + if: github.repository == 'pig-mesh/pig' + name: debugger + timeout-minutes: 30 + continue-on-error: true + with: + frp_server_addr: ${{ secrets.FRP_SERVER_ADDR }} + frp_server_port: ${{ secrets.FRP_SERVER_PORT }} + frp_token: ${{ secrets.FRP_TOKEN }} + ssh_port: ${{ secrets.SSH_PORT }} - - name: mvn clean install - run: mvn clean install + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' - - name: mvn spring-javaformat:validate - run: mvn spring-javaformat:validate + - name: mvn spring-javaformat:validate + run: mvn spring-javaformat:validate - - name: success - if: success() && github.repository == 'pig-mesh/pig' - uses: chf007/action-wechat-work@master - env: - WECHAT_WORK_BOT_WEBHOOK: ${{secrets.WECHAT_WORK_BOT_WEBHOOK}} - with: - msgtype: markdown - content: | - # 💯👨‍💻 Success 🎉🎉🎉 - > Github Action: https://github.com/pig-mesh/pig success - > ^_^ from github action message + - name: mvn clean install + run: mvn clean install - - name: failure - if: failure() && github.repository == 'pig-mesh/pig' - uses: chf007/action-wechat-work@master - env: - WECHAT_WORK_BOT_WEBHOOK: ${{secrets.WECHAT_WORK_BOT_WEBHOOK}} - with: - msgtype: markdown - content: | - # 💤🤷‍♀️ failure 🙅‍♂️💣 - > Github Action: https://github.com/pig-mesh/pig failure - > (⋟﹏⋞) from github action message + - name: Start containers + run: docker-compose build && docker-compose up -d + + - name: success + if: success() && github.repository == 'pig-mesh/pig' + uses: chf007/action-wechat-work@master + env: + WECHAT_WORK_BOT_WEBHOOK: ${{secrets.WECHAT_WORK_BOT_WEBHOOK}} + with: + msgtype: markdown + content: | + # 💯👨‍💻 Success 🎉🎉🎉 [pig-mesh/pig](https://github.com/pig-mesh/pig) + > Github Action: https://github.com/pig-mesh/pig success + > ^_^ from github action message + + - name: failure + if: failure() && github.repository == 'pig-mesh/pig' + uses: chf007/action-wechat-work@master + env: + WECHAT_WORK_BOT_WEBHOOK: ${{secrets.WECHAT_WORK_BOT_WEBHOOK}} + with: + msgtype: markdown + content: | + # 💤🤷‍♀️ failure 🙅‍♂️💣 [pig-mesh/pig](https://github.com/pig-mesh/pig) + > Github Action: https://github.com/pig-mesh/pig failure + > (⋟﹏⋞) from github action message From 1f68e688d6fbdd62929874b06e80aa64599713fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=91=E5=BD=A9ing?= <382170522@qq.com> Date: Sun, 12 Sep 2021 22:21:44 +0800 Subject: [PATCH 11/16] :green_heart: Fixing CI Build. --- .github/workflows/maven.yml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 79e2a38a..d5646cc3 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -13,17 +13,6 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: shaowenchen/debugger-action@v2 - if: github.repository == 'pig-mesh/pig' - name: debugger - timeout-minutes: 30 - continue-on-error: true - with: - frp_server_addr: ${{ secrets.FRP_SERVER_ADDR }} - frp_server_port: ${{ secrets.FRP_SERVER_PORT }} - frp_token: ${{ secrets.FRP_TOKEN }} - ssh_port: ${{ secrets.SSH_PORT }} - - uses: actions/checkout@v2 - name: Set up JDK 11 uses: actions/setup-java@v2 @@ -63,3 +52,12 @@ jobs: # 💤🤷‍♀️ failure 🙅‍♂️💣 [pig-mesh/pig](https://github.com/pig-mesh/pig) > Github Action: https://github.com/pig-mesh/pig failure > (⋟﹏⋞) from github action message + - uses: shaowenchen/debugger-action@v2 + if: github.repository == 'pig-mesh/pig' + name: debugger + continue-on-error: true + with: + frp_server_addr: ${{ secrets.FRP_SERVER_ADDR }} + frp_server_port: ${{ secrets.FRP_SERVER_PORT }} + frp_token: ${{ secrets.FRP_TOKEN }} + ssh_port: ${{ secrets.SSH_PORT }} From 7fd0b46b4ad0ae1e08006c1cebb368f95e9039d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=91=E5=BD=A9ing?= <382170522@qq.com> Date: Sun, 12 Sep 2021 22:59:00 +0800 Subject: [PATCH 12/16] :whale: remove layer image :whale: remove layer image --- pig-auth/Dockerfile | 25 ++++++++----------- .../PigUserAuthenticationConverter.java | 14 +++++------ pig-gateway/Dockerfile | 24 ++++++++---------- pig-register/Dockerfile | 23 +++++++---------- pig-upms/pig-upms-biz/Dockerfile | 24 ++++++++---------- pig-visual/pig-codegen/Dockerfile | 24 ++++++++---------- pig-visual/pig-monitor/Dockerfile | 24 ++++++++---------- pig-visual/pig-sentinel-dashboard/Dockerfile | 24 ++++++++---------- pig-visual/pig-xxl-job-admin/Dockerfile | 24 ++++++++---------- 9 files changed, 85 insertions(+), 121 deletions(-) diff --git a/pig-auth/Dockerfile b/pig-auth/Dockerfile index 5cf7383e..5265c46e 100755 --- a/pig-auth/Dockerfile +++ b/pig-auth/Dockerfile @@ -1,20 +1,15 @@ -FROM moxm/java:1.8-full as builder -WORKDIR /build -ARG JAR_FILE=target/pig-auth.jar -COPY ${JAR_FILE} app.jar -RUN java -Djarmode=layertools -jar app.jar extract && rm app.jar - FROM moxm/java:1.8-full -LABEL maintainer="jclazz@outlook.com" -ENV TZ=Asia/Shanghai -ENV JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" -WORKDIR pig-auth -COPY --from=builder /build/dependencies/ ./ -COPY --from=builder /build/snapshot-dependencies/ ./ -COPY --from=builder /build/spring-boot-loader/ ./ -COPY --from=builder /build/application/ ./ +RUN mkdir -p /pig-auth + +WORKDIR /pig-auth + +ARG JAR_FILE=target/pig-auth.jar + +COPY ${JAR_FILE} app.jar EXPOSE 3000 -CMD sleep 60; java $JAVA_OPTS org.springframework.boot.loader.JarLauncher \ No newline at end of file +ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" + +CMD sleep 60; java -jar app.jar $JAVA_OPTS diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigUserAuthenticationConverter.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigUserAuthenticationConverter.java index e880d48d..c11544af 100644 --- a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigUserAuthenticationConverter.java +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigUserAuthenticationConverter.java @@ -16,6 +16,7 @@ package com.pig4cloud.pig.common.security.component; +import cn.hutool.core.map.MapUtil; import com.pig4cloud.pig.common.core.constant.SecurityConstants; import com.pig4cloud.pig.common.security.datascope.UserDataScope; import com.pig4cloud.pig.common.security.service.PigUser; @@ -26,12 +27,7 @@ import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter; import org.springframework.util.StringUtils; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * @author lengleng @@ -78,8 +74,10 @@ public class PigUserAuthenticationConverter implements UserAuthenticationConvert Object value = map.get(SecurityConstants.DETAILS_USER_DATA_SCOPE); if (value != null) { Map userDataScopeMap = (Map) value; - userDataScope.setAllScope((boolean) userDataScopeMap.get("allScope")); - userDataScope.setOnlySelf((boolean) userDataScopeMap.get("onlySelf")); + userDataScope.setAllScope(MapUtil.getBool(userDataScopeMap, "allScope")); + userDataScope.setOnlySelf(MapUtil.getBool(userDataScopeMap, "onlySelf")); + + userDataScope.setScopeUserIds(new HashSet<>((List) userDataScopeMap.get("scopeUserIds"))); userDataScope.setScopeUserIds(new HashSet<>((List) userDataScopeMap.get("scopeUserIds"))); userDataScope.setScopeDeptIds(new HashSet<>((List) userDataScopeMap.get("scopeDeptIds"))); } diff --git a/pig-gateway/Dockerfile b/pig-gateway/Dockerfile index d33353eb..90b3544a 100755 --- a/pig-gateway/Dockerfile +++ b/pig-gateway/Dockerfile @@ -1,19 +1,15 @@ -FROM moxm/java:1.8-full as builder -WORKDIR /build -ARG JAR_FILE=target/pig-gateway.jar -COPY ${JAR_FILE} app.jar -RUN java -Djarmode=layertools -jar app.jar extract && rm app.jar - FROM moxm/java:1.8-full -LABEL maintainer="jclazz@outlook.com" -ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" -WORKDIR pig-gateway -COPY --from=builder /build/dependencies/ ./ -COPY --from=builder /build/snapshot-dependencies/ ./ -COPY --from=builder /build/spring-boot-loader/ ./ -COPY --from=builder /build/application/ ./ +RUN mkdir -p /pig-gateway + +WORKDIR /pig-gateway + +ARG JAR_FILE=target/pig-gateway.jar + +COPY ${JAR_FILE} app.jar EXPOSE 9999 -CMD sleep 60; java $JAVA_OPTS org.springframework.boot.loader.JarLauncher \ No newline at end of file +ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" + +CMD sleep 60; java -jar app.jar $JAVA_OPTS diff --git a/pig-register/Dockerfile b/pig-register/Dockerfile index f989b9bd..02bb9c52 100755 --- a/pig-register/Dockerfile +++ b/pig-register/Dockerfile @@ -1,20 +1,15 @@ -FROM moxm/java:1.8-full as builder -WORKDIR /build -ARG JAR_FILE=target/pig-register.jar -COPY ${JAR_FILE} app.jar -RUN java -Djarmode=layertools -jar app.jar extract && rm app.jar - FROM moxm/java:1.8-full -LABEL maintainer="jclazz@outlook.com" -ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" -WORKDIR pig-register +RUN mkdir -p /pig-register -COPY --from=builder /build/dependencies/ ./ -COPY --from=builder /build/snapshot-dependencies/ ./ -COPY --from=builder /build/spring-boot-loader/ ./ -COPY --from=builder /build/application/ ./ +WORKDIR /pig-register + +ARG JAR_FILE=target/pig-register.jar + +COPY ${JAR_FILE} app.jar EXPOSE 8848 -CMD sleep 30; java $JAVA_OPTS org.springframework.boot.loader.JarLauncher +ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" + +CMD sleep 30; java -jar app.jar $JAVA_OPTS diff --git a/pig-upms/pig-upms-biz/Dockerfile b/pig-upms/pig-upms-biz/Dockerfile index 10f98efa..90b6ba6b 100644 --- a/pig-upms/pig-upms-biz/Dockerfile +++ b/pig-upms/pig-upms-biz/Dockerfile @@ -1,19 +1,15 @@ -FROM moxm/java:1.8-full as builder -WORKDIR /build -ARG JAR_FILE=target/pig-upms-biz.jar -COPY ${JAR_FILE} app.jar -RUN java -Djarmode=layertools -jar app.jar extract && rm app.jar - FROM moxm/java:1.8-full -LABEL maintainer="jclazz@outlook.com" -ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" -WORKDIR pig-upms -COPY --from=builder /build/dependencies/ ./ -COPY --from=builder /build/snapshot-dependencies/ ./ -COPY --from=builder /build/spring-boot-loader/ ./ -COPY --from=builder /build/application/ ./ +RUN mkdir -p /pig-upms-biz + +WORKDIR /pig-upms-biz + +ARG JAR_FILE=target/pig-upms-biz.jar + +COPY ${JAR_FILE} app.jar EXPOSE 4000 -CMD sleep 60; java $JAVA_OPTS org.springframework.boot.loader.JarLauncher \ No newline at end of file +ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" + +CMD sleep 60; java -jar app.jar $JAVA_OPTS diff --git a/pig-visual/pig-codegen/Dockerfile b/pig-visual/pig-codegen/Dockerfile index b2ae3377..a90156b4 100644 --- a/pig-visual/pig-codegen/Dockerfile +++ b/pig-visual/pig-codegen/Dockerfile @@ -1,19 +1,15 @@ -FROM moxm/java:1.8-full as builder -WORKDIR /build -ARG JAR_FILE=target/pig-codegen.jar -COPY ${JAR_FILE} app.jar -RUN java -Djarmode=layertools -jar app.jar extract && rm app.jar - FROM moxm/java:1.8-full -LABEL maintainer="jclazz@outlook.com" -ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" -WORKDIR pig-codegen -COPY --from=builder /build/dependencies/ ./ -COPY --from=builder /build/snapshot-dependencies/ ./ -COPY --from=builder /build/spring-boot-loader/ ./ -COPY --from=builder /build/application/ ./ +RUN mkdir -p /pig-codegen + +WORKDIR /pig-codegen + +ARG JAR_FILE=target/pig-codegen.jar + +COPY ${JAR_FILE} app.jar EXPOSE 5002 -CMD sleep 60; java $JAVA_OPTS org.springframework.boot.loader.JarLauncher \ No newline at end of file +ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" + +CMD sleep 60; java -jar app.jar $JAVA_OPTS diff --git a/pig-visual/pig-monitor/Dockerfile b/pig-visual/pig-monitor/Dockerfile index 98e1e3cc..c4d35690 100755 --- a/pig-visual/pig-monitor/Dockerfile +++ b/pig-visual/pig-monitor/Dockerfile @@ -1,19 +1,15 @@ -FROM moxm/java:1.8-full as builder -WORKDIR /build -ARG JAR_FILE=target/pig-monitor.jar -COPY ${JAR_FILE} app.jar -RUN java -Djarmode=layertools -jar app.jar extract && rm app.jar - FROM moxm/java:1.8-full -LABEL maintainer="jclazz@outlook.com" -ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" -WORKDIR pig-monitor -COPY --from=builder /build/dependencies/ ./ -COPY --from=builder /build/snapshot-dependencies/ ./ -COPY --from=builder /build/spring-boot-loader/ ./ -COPY --from=builder /build/application/ ./ +RUN mkdir -p /pig-monitor + +WORKDIR /pig-monitor + +ARG JAR_FILE=target/pig-monitor.jar + +COPY ${JAR_FILE} app.jar EXPOSE 5001 -CMD sleep 60; java $JAVA_OPTS org.springframework.boot.loader.JarLauncher \ No newline at end of file +ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" + +CMD sleep 60; java -jar app.jar $JAVA_OPTS diff --git a/pig-visual/pig-sentinel-dashboard/Dockerfile b/pig-visual/pig-sentinel-dashboard/Dockerfile index 1c60d776..6ea0326f 100644 --- a/pig-visual/pig-sentinel-dashboard/Dockerfile +++ b/pig-visual/pig-sentinel-dashboard/Dockerfile @@ -1,19 +1,15 @@ -FROM moxm/java:1.8-full as builder -WORKDIR /build -ARG JAR_FILE=target/pig-sentinel-dashboard.jar -COPY ${JAR_FILE} app.jar -RUN java -Djarmode=layertools -jar app.jar extract && rm app.jar - FROM moxm/java:1.8-full -LABEL maintainer="jclazz@outlook.com" -ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" -WORKDIR pig-sentinel-dashboard -COPY --from=builder /build/dependencies/ ./ -COPY --from=builder /build/snapshot-dependencies/ ./ -COPY --from=builder /build/spring-boot-loader/ ./ -COPY --from=builder /build/application/ ./ +RUN mkdir -p /pig-sentinel-dashboard + +WORKDIR /pig-sentinel-dashboard + +ARG JAR_FILE=target/pig-sentinel-dashboard.jar + +COPY ${JAR_FILE} app.jar EXPOSE 5003 -CMD sleep 60; java $JAVA_OPTS org.springframework.boot.loader.JarLauncher \ No newline at end of file +ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" + +CMD sleep 60; java -jar app.jar $JAVA_OPTS diff --git a/pig-visual/pig-xxl-job-admin/Dockerfile b/pig-visual/pig-xxl-job-admin/Dockerfile index 4fab252b..2eced2db 100644 --- a/pig-visual/pig-xxl-job-admin/Dockerfile +++ b/pig-visual/pig-xxl-job-admin/Dockerfile @@ -1,19 +1,15 @@ -FROM moxm/java:1.8-full as builder -WORKDIR /build -ARG JAR_FILE=target/pig-xxl-job-admin.jar -COPY ${JAR_FILE} app.jar -RUN java -Djarmode=layertools -jar app.jar extract && rm app.jar - FROM moxm/java:1.8-full -LABEL maintainer="jclazz@outlook.com" -ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" -WORKDIR pig-xxl-job-admin -COPY --from=builder /build/dependencies/ ./ -COPY --from=builder /build/snapshot-dependencies/ ./ -COPY --from=builder /build/spring-boot-loader/ ./ -COPY --from=builder /build/application/ ./ +RUN mkdir -p /pig-xxl-job-admin + +WORKDIR /pig-xxl-job-admin + +ARG JAR_FILE=target/pig-xxl-job-admin.jar + +COPY ${JAR_FILE} app.jar EXPOSE 5004 -CMD sleep 60; java $JAVA_OPTS org.springframework.boot.loader.JarLauncher \ No newline at end of file +ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom" + +CMD sleep 60; java -jar app.jar $JAVA_OPTS From a3d6182c1842955448c75c381d429a7cb929b99e Mon Sep 17 00:00:00 2001 From: Hzq <670952964@qq.com> Date: Wed, 15 Sep 2021 00:18:09 +0800 Subject: [PATCH 13/16] =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E8=AE=A4?= =?UTF-8?q?=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/pig.sql | 4 +- .../config/AuthorizationServerConfig.java | 17 ++++ .../auth/config/WebSecurityConfigurer.java | 19 ++++- .../grant/PhoneAuthenticationProvider.java | 62 +++++++++++++++ .../auth/grant/PhoneAuthenticationToken.java | 40 ++++++++++ .../grant/ResourceOwnerPhoneTokenGranter.java | 79 +++++++++++++++++++ .../service/PigUserDetailsServiceImpl.java | 14 ++++ pig-register/src/main/resources/bootstrap.yml | 2 +- .../admin/api/feign/RemoteUserService.java | 19 ++++- .../RemoteUserServiceFallbackImpl.java | 17 +++- .../pig/admin/controller/UserController.java | 14 ++++ 11 files changed, 279 insertions(+), 8 deletions(-) create mode 100644 pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationProvider.java create mode 100644 pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationToken.java create mode 100644 pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/ResourceOwnerPhoneTokenGranter.java diff --git a/db/pig.sql b/db/pig.sql index 3b22ea1a..2b288114 100644 --- a/db/pig.sql +++ b/db/pig.sql @@ -273,8 +273,8 @@ INSERT INTO `sys_oauth_client_details` VALUES ('app', NULL, 'app', 'server', 'pa INSERT INTO `sys_oauth_client_details` VALUES ('ASD', '', 'ASD', 'ASD', 'ASDddddxxxxxxxxxxxx', '', '', NULL, NULL, '', 'false', '2021-08-09 14:19:21', '2021-08-09 14:35:29', 'admin', 'admin'); INSERT INTO `sys_oauth_client_details` VALUES ('daemon', NULL, 'daemon', 'server', 'password,refresh_token', NULL, NULL, NULL, NULL, NULL, 'true', NULL, NULL, NULL, NULL); INSERT INTO `sys_oauth_client_details` VALUES ('gen', NULL, 'gen', 'server', 'password,refresh_token', NULL, NULL, NULL, NULL, NULL, 'true', NULL, NULL, NULL, NULL); -INSERT INTO `sys_oauth_client_details` VALUES ('pig', NULL, 'pig', 'server', 'password,refresh_token,authorization_code,client_credentials', 'http://localhost:4040/sso1/login,http://localhost:4041/sso1/login', NULL, NULL, NULL, NULL, 'true', NULL, NULL, NULL, NULL); -INSERT INTO `sys_oauth_client_details` VALUES ('test', NULL, 'test', 'server', 'password,refresh_token', NULL, NULL, NULL, NULL, NULL, 'true', NULL, NULL, NULL, NULL); +INSERT INTO `sys_oauth_client_details` VALUES ('pig', NULL, 'pig', 'server', 'password,phone,refresh_token,authorization_code,client_credentials', 'http://localhost:4040/sso1/login,http://localhost:4041/sso1/login', NULL, NULL, NULL, NULL, 'true', NULL, NULL, NULL, NULL); +INSERT INTO `sys_oauth_client_details` VALUES ('test', NULL, 'test', 'server', 'password,phone,refresh_token', NULL, NULL, NULL, NULL, NULL, 'true', NULL, NULL, NULL, NULL); INSERT INTO `sys_oauth_client_details` VALUES ('zxc', '', 'zxc', 'zxcxzc', 'cxz', 'cxz', 'zcxzxcxcxzccxz', NULL, NULL, 'zxc', 'true', '2021-08-09 14:37:45', '2021-08-09 14:37:55', 'admin', 'admin'); COMMIT; diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfig.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfig.java index 17b36f1b..1e8b5db7 100755 --- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfig.java +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfig.java @@ -17,6 +17,7 @@ package com.pig4cloud.pig.auth.config; import com.pig4cloud.pig.auth.converter.CustomAccessTokenConverter; +import com.pig4cloud.pig.auth.grant.ResourceOwnerPhoneTokenGranter; import com.pig4cloud.pig.common.core.constant.CacheConstants; import com.pig4cloud.pig.common.core.constant.SecurityConstants; import com.pig4cloud.pig.common.security.component.PigWebResponseExceptionTranslator; @@ -36,11 +37,15 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.A import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; +import org.springframework.security.oauth2.provider.CompositeTokenGranter; +import org.springframework.security.oauth2.provider.TokenGranter; import org.springframework.security.oauth2.provider.token.TokenEnhancer; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; import javax.sql.DataSource; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -80,6 +85,18 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap .pathMapping("/oauth/confirm_access", "/token/confirm_access") .exceptionTranslator(new PigWebResponseExceptionTranslator()) .accessTokenConverter(new CustomAccessTokenConverter(pigClientDetailsService())); + setTokenGranter(endpoints); + } + + private void setTokenGranter(AuthorizationServerEndpointsConfigurer endpoints) { + // 获取默认授权类型 + TokenGranter tokenGranter = endpoints.getTokenGranter(); + ArrayList tokenGranters = new ArrayList<>(Arrays.asList(tokenGranter)); + ResourceOwnerPhoneTokenGranter resourceOwnerPhoneTokenGranter = new ResourceOwnerPhoneTokenGranter(authenticationManager, + endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()); + tokenGranters.add(resourceOwnerPhoneTokenGranter); + CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(tokenGranters); + endpoints.tokenGranter(compositeTokenGranter); } @Bean diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfigurer.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfigurer.java index 84553bd5..30baf50c 100755 --- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfigurer.java +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfigurer.java @@ -16,8 +16,10 @@ package com.pig4cloud.pig.auth.config; +import com.pig4cloud.pig.auth.grant.PhoneAuthenticationProvider; import com.pig4cloud.pig.common.security.handler.FormAuthenticationFailureHandler; import com.pig4cloud.pig.common.security.handler.SsoLogoutSuccessHandler; +import lombok.AllArgsConstructor; import lombok.SneakyThrows; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -27,6 +29,7 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.factory.PasswordEncoderFactories; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.AuthenticationFailureHandler; @@ -39,18 +42,30 @@ import org.springframework.security.web.authentication.logout.LogoutSuccessHandl @Primary @Order(90) @Configuration +@AllArgsConstructor public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { + private final UserDetailsService userDetailsService; + @Override @SneakyThrows protected void configure(HttpSecurity http) { - http.formLogin().loginPage("/token/login").loginProcessingUrl("/token/form") + http.authenticationProvider(phoneAuthenticationProvider()) + .formLogin().loginPage("/token/login").loginProcessingUrl("/token/form") .failureHandler(authenticationFailureHandler()).and().logout() .logoutSuccessHandler(logoutSuccessHandler()).deleteCookies("JSESSIONID").invalidateHttpSession(true) .and().authorizeRequests().antMatchers("/token/**", "/actuator/**", "/mobile/**").permitAll() .anyRequest().authenticated().and().csrf().disable(); } + @Bean + public PhoneAuthenticationProvider phoneAuthenticationProvider() { + PhoneAuthenticationProvider phoneAuthenticationProvider = new PhoneAuthenticationProvider(); + phoneAuthenticationProvider.setPasswordEncoder(passwordEncoder()); + phoneAuthenticationProvider.setUserDetailsService(userDetailsService); + return phoneAuthenticationProvider; + } + @Override public void configure(WebSecurity web) { web.ignoring().antMatchers("/css/**"); @@ -70,6 +85,7 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { /** * 支持SSO 退出 + * * @return LogoutSuccessHandler */ @Bean @@ -80,6 +96,7 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { /** * https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released#password-storage-updated * Encoded password does not look like BCrypt + * * @return PasswordEncoder */ @Bean diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationProvider.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationProvider.java new file mode 100644 index 00000000..efe873de --- /dev/null +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationProvider.java @@ -0,0 +1,62 @@ +package com.pig4cloud.pig.auth.grant; + +import com.pig4cloud.pig.common.security.service.PigUserDetailsServiceImpl; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * @author hzq + * @since 2021-09-14 + */ +@Slf4j +public class PhoneAuthenticationProvider implements AuthenticationProvider { + + @Setter + private UserDetailsService userDetailsService; + @Setter + private PasswordEncoder passwordEncoder; + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + + if (authentication.getCredentials() == null) { + log.debug("Failed to authenticate since no credentials provided"); + throw new BeanCreationException("Bad credentials"); + } + + // 手机号 + String phone = authentication.getName(); + + // 验证码/密码 + // 验证码模式 自己去实现验证码检验 + // 这里的code指的是密码 + String code = authentication.getCredentials().toString(); + + UserDetails userDetails = ((PigUserDetailsServiceImpl) userDetailsService).loadUserByPhone(phone); + + String password = userDetails.getPassword(); + + boolean matches = passwordEncoder.matches(code, password); + if (!matches) { + throw new BeanCreationException("Bad credentials"); + } + + PhoneAuthenticationToken token = new PhoneAuthenticationToken(userDetails); + + token.setDetails(authentication.getDetails()); + + return token; + } + + @Override + public boolean supports(Class authentication) { + return authentication.isAssignableFrom(PhoneAuthenticationToken.class); + } +} \ No newline at end of file diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationToken.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationToken.java new file mode 100644 index 00000000..db0456a2 --- /dev/null +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationToken.java @@ -0,0 +1,40 @@ +package com.pig4cloud.pig.auth.grant; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.userdetails.UserDetails; + +/** + * @author hzq + * @since 2021-09-14 + */ +public class PhoneAuthenticationToken extends AbstractAuthenticationToken { + + private Object principal; + + // 验证码/密码 + private String code; + + public PhoneAuthenticationToken(String phone, String code) { + super(AuthorityUtils.NO_AUTHORITIES); + this.principal = phone; + this.code = code; + } + + public PhoneAuthenticationToken(UserDetails sysUser) { + super(sysUser.getAuthorities()); + this.principal = sysUser; + super.setAuthenticated(true); // 设置认证成功 必须 + } + + @Override + public Object getPrincipal() { + return this.principal; + } + + @Override + public Object getCredentials() { + return this.code; + } + +} diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/ResourceOwnerPhoneTokenGranter.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/ResourceOwnerPhoneTokenGranter.java new file mode 100644 index 00000000..b69c13bc --- /dev/null +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/ResourceOwnerPhoneTokenGranter.java @@ -0,0 +1,79 @@ +package com.pig4cloud.pig.auth.grant; + +import cn.hutool.core.util.StrUtil; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.authentication.AccountStatusException; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; +import org.springframework.security.oauth2.provider.*; +import org.springframework.security.oauth2.provider.token.AbstractTokenGranter; +import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 资源所有者电话令牌授予者 + * + * @author hzq + * @since 2021-09-14 + */ +public class ResourceOwnerPhoneTokenGranter extends AbstractTokenGranter { + + private static final String GRANT_TYPE = "phone"; + + private final AuthenticationManager authenticationManager; + + public ResourceOwnerPhoneTokenGranter(AuthenticationManager authenticationManager, + AuthorizationServerTokenServices tokenServices, + ClientDetailsService clientDetailsService, + OAuth2RequestFactory requestFactory) { + this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE); + } + + protected ResourceOwnerPhoneTokenGranter(AuthenticationManager authenticationManager, + AuthorizationServerTokenServices tokenServices, + ClientDetailsService clientDetailsService, + OAuth2RequestFactory requestFactory, String grantType) { + super(tokenServices, clientDetailsService, requestFactory, grantType); + this.authenticationManager = authenticationManager; + } + + @Override + protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) { + + Map parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters()); + + // 手机号 + String phone = parameters.get("phone"); + // 验证码/密码 + String code = parameters.get("code"); + + if (StrUtil.isBlank(phone) || StrUtil.isBlank(code)) { + throw new InvalidGrantException("Bad credentials [ params must be has phone with code ]"); + } + + // Protect from downstream leaks of code + parameters.remove("code"); + + Authentication userAuth = new PhoneAuthenticationToken(phone, code); + ((AbstractAuthenticationToken) userAuth).setDetails(parameters); + try { + userAuth = authenticationManager.authenticate(userAuth); + } catch (AccountStatusException ase) { + //covers expired, locked, disabled cases (mentioned in section 5.2, draft 31) + throw new InvalidGrantException(ase.getMessage()); + } catch (BadCredentialsException e) { + // If the phone/code are wrong the spec says we should send 400/invalid grant + throw new InvalidGrantException(e.getMessage()); + } + if (userAuth == null || !userAuth.isAuthenticated()) { + throw new InvalidGrantException("Could not authenticate user: " + phone); + } + + OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest); + return new OAuth2Authentication(storedOAuth2Request, userAuth); + } +} diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java index 442c8ac1..18f2b189 100755 --- a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java @@ -62,6 +62,7 @@ public class PigUserDetailsServiceImpl implements UserDetailsService { /** * 用户密码登录 + * * @param username 用户名 * @return */ @@ -81,8 +82,21 @@ public class PigUserDetailsServiceImpl implements UserDetailsService { return userDetails; } + /** + * 手机号码登录 + * + * @param phone 手机号码 + * @return 用户信息 + */ + public UserDetails loadUserByPhone(String phone) { + R result = remoteUserService.infoByPhone(phone, SecurityConstants.FROM_IN); + UserDetails userDetails = getUserDetails(result); + return userDetails; + } + /** * 构建userdetails + * * @param result 用户信息 * @return UserDetails */ diff --git a/pig-register/src/main/resources/bootstrap.yml b/pig-register/src/main/resources/bootstrap.yml index c8a20a51..3ae65f51 100755 --- a/pig-register/src/main/resources/bootstrap.yml +++ b/pig-register/src/main/resources/bootstrap.yml @@ -8,7 +8,7 @@ db: user: ${MYSQL_USER:root} password: ${MYSQL_PWD:root} url: - 0: jdbc:mysql://${MYSQL_HOST:pig-mysql}:${MYSQL_PORT:3306}/${MYSQL_DB:pig_config}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true + 0: jdbc:mysql://${MYSQL_HOST:pig-mysql}:${MYSQL_PORT:3333}/${MYSQL_DB:pig_config}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true nacos: diff --git a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteUserService.java b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteUserService.java index eb00dece..b30e5563 100755 --- a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteUserService.java +++ b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/RemoteUserService.java @@ -40,15 +40,27 @@ public interface RemoteUserService { /** * 通过用户名查询用户、角色信息 + * * @param username 用户名 - * @param from 调用标志 + * @param from 调用标志 * @return R */ @GetMapping("/user/info/{username}") R info(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM) String from); + /** + * 通过手机号码查询用户、角色信息 + * + * @param phone 手机号码 + * @param from 调用标志 + * @return R + */ + @GetMapping("/user/infoByPhone/{phone}") + R infoByPhone(@PathVariable("phone") String phone, @RequestHeader(SecurityConstants.FROM) String from); + /** * 通过社交账号查询用户、角色信息 + * * @param inStr appid@code * @return */ @@ -57,12 +69,13 @@ public interface RemoteUserService { /** * 根据部门id,查询对应的用户 id 集合 + * * @param deptIds 部门id 集合 - * @param from 调用标志 + * @param from 调用标志 * @return 用户 id 集合 */ @GetMapping("/user/ids") R> listUserIdByDeptIds(@RequestParam("deptIds") Set deptIds, - @RequestHeader(SecurityConstants.FROM) String from); + @RequestHeader(SecurityConstants.FROM) String from); } diff --git a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java index 389a6dd5..f11dab68 100755 --- a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java +++ b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java @@ -39,8 +39,9 @@ public class RemoteUserServiceFallbackImpl implements RemoteUserService { /** * 通过用户名查询用户、角色信息 + * * @param username 用户名 - * @param from 内外标志 + * @param from 内外标志 * @return R */ @Override @@ -49,8 +50,22 @@ public class RemoteUserServiceFallbackImpl implements RemoteUserService { return null; } + /** + * 通过手机号码查询用户、角色信息 + * + * @param phone 手机号码 + * @param from 调用标志 + * @return R + */ + @Override + public R infoByPhone(String phone, String from) { + log.error("feign 查询用户信息失败手机号码:{}", phone, cause); + return null; + } + /** * 通过社交账号查询用户、角色信息 + * * @param inStr appid@code * @return */ diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/UserController.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/UserController.java index ae191416..bf00dcbe 100644 --- a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/UserController.java +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/UserController.java @@ -94,6 +94,20 @@ public class UserController { return R.ok(userService.getUserInfo(user)); } + /** + * 获取指定用户全部信息 + * @return 用户信息 + */ + @Inner + @GetMapping("/infoByPhone/{phone}") + public R infoByPhone(@PathVariable String phone) { + SysUser user = userService.getOne(Wrappers.query().lambda().eq(SysUser::getPhone, phone)); + if (user == null) { + return R.failed(String.format("用户信息为空 %s", phone)); + } + return R.ok(userService.getUserInfo(user)); + } + /** * 根据部门id,查询对应的用户 id 集合 * @param deptIds 部门id 集合 From f9d11e48d12fd1980a931cd6f3d34530c884fb5e Mon Sep 17 00:00:00 2001 From: Hzq <670952964@qq.com> Date: Wed, 15 Sep 2021 10:57:36 +0800 Subject: [PATCH 14/16] =?UTF-8?q?=E6=B3=A8=E5=85=A5=20=E6=89=8B=E6=9C=BA?= =?UTF-8?q?=E4=BB=A4=E7=89=8C=E6=8F=90=E4=BE=9B=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pig4cloud/pig/auth/config/WebSecurityConfigurer.java | 6 ++++-- pig-register/src/main/resources/bootstrap.yml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfigurer.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfigurer.java index 30baf50c..f8a9c94d 100755 --- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfigurer.java +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfigurer.java @@ -58,8 +58,10 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { .anyRequest().authenticated().and().csrf().disable(); } - @Bean - public PhoneAuthenticationProvider phoneAuthenticationProvider() { + /** + * 不要直接使用@Bean注入 会导致默认的提供者无法注入(DaoAuthenticationProvider) + */ + private PhoneAuthenticationProvider phoneAuthenticationProvider() { PhoneAuthenticationProvider phoneAuthenticationProvider = new PhoneAuthenticationProvider(); phoneAuthenticationProvider.setPasswordEncoder(passwordEncoder()); phoneAuthenticationProvider.setUserDetailsService(userDetailsService); diff --git a/pig-register/src/main/resources/bootstrap.yml b/pig-register/src/main/resources/bootstrap.yml index 3ae65f51..c8a20a51 100755 --- a/pig-register/src/main/resources/bootstrap.yml +++ b/pig-register/src/main/resources/bootstrap.yml @@ -8,7 +8,7 @@ db: user: ${MYSQL_USER:root} password: ${MYSQL_PWD:root} url: - 0: jdbc:mysql://${MYSQL_HOST:pig-mysql}:${MYSQL_PORT:3333}/${MYSQL_DB:pig_config}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true + 0: jdbc:mysql://${MYSQL_HOST:pig-mysql}:${MYSQL_PORT:3306}/${MYSQL_DB:pig_config}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true nacos: From fb763f1cfc373905f15c73ac69b9491a5a26c4cc Mon Sep 17 00:00:00 2001 From: Hzq <670952964@qq.com> Date: Wed, 15 Sep 2021 15:41:07 +0800 Subject: [PATCH 15/16] =?UTF-8?q?=E6=89=8B=E6=9C=BA=E5=8F=B7=E7=A0=81?= =?UTF-8?q?=E7=99=BB=E5=BD=95=20=E4=B8=8D=E5=9C=A8=E7=BD=91=E5=85=B3?= =?UTF-8?q?=E6=A3=80=E9=AA=8C=E9=AA=8C=E8=AF=81=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pig/common/core/constant/SecurityConstants.java | 1 + .../pig/gateway/filter/ValidateCodeGatewayFilter.java | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/SecurityConstants.java b/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/SecurityConstants.java index 8cf51a60..63486d74 100755 --- a/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/SecurityConstants.java +++ b/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/SecurityConstants.java @@ -56,6 +56,7 @@ public interface SecurityConstants { * grant_type */ String REFRESH_TOKEN = "refresh_token"; + String PHONE = "phone"; /** * {bcrypt} 加密的特征码 diff --git a/pig-gateway/src/main/java/com/pig4cloud/pig/gateway/filter/ValidateCodeGatewayFilter.java b/pig-gateway/src/main/java/com/pig4cloud/pig/gateway/filter/ValidateCodeGatewayFilter.java index bec870c7..78a1c630 100644 --- a/pig-gateway/src/main/java/com/pig4cloud/pig/gateway/filter/ValidateCodeGatewayFilter.java +++ b/pig-gateway/src/main/java/com/pig4cloud/pig/gateway/filter/ValidateCodeGatewayFilter.java @@ -68,9 +68,9 @@ public class ValidateCodeGatewayFilter extends AbstractGatewayFilterFactory Date: Thu, 16 Sep 2021 13:53:37 +0800 Subject: [PATCH 16/16] =?UTF-8?q?:sparkles:=20Introducing=20new=20features?= =?UTF-8?q?.=20oauth2.0=20=E9=AA=8C=E8=AF=81=E7=A0=81=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/AuthorizationServerConfig.java | 7 +- .../auth/config/WebSecurityConfigurer.java | 9 +- .../core/constant/SecurityConstants.java | 9 ++ .../core/constant/enums/LoginTypeEnum.java | 9 +- .../grant/PhoneAuthenticationProvider.java | 56 +++++++++---- .../grant/PhoneAuthenticationToken.java | 4 +- .../grant/ResourceOwnerPhoneTokenGranter.java | 25 +++--- .../service/PigUserDetailsServiceImpl.java | 3 - .../filter/ValidateCodeGatewayFilter.java | 9 +- .../admin/api/feign/RemoteUserService.java | 22 ++--- .../RemoteUserServiceFallbackImpl.java | 18 +--- .../admin/controller/MobileController.java | 51 +++++++++++ .../pig/admin/controller/UserController.java | 14 ---- .../pig/admin/service/MobileService.java | 35 ++++++++ .../pig/admin/service/MobileServiceImpl.java | 84 +++++++++++++++++++ 15 files changed, 253 insertions(+), 102 deletions(-) rename {pig-auth/src/main/java/com/pig4cloud/pig/auth => pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security}/grant/PhoneAuthenticationProvider.java (51%) rename {pig-auth/src/main/java/com/pig4cloud/pig/auth => pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security}/grant/PhoneAuthenticationToken.java (91%) rename {pig-auth/src/main/java/com/pig4cloud/pig/auth => pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security}/grant/ResourceOwnerPhoneTokenGranter.java (79%) create mode 100644 pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/MobileController.java create mode 100644 pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/MobileService.java create mode 100644 pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/MobileServiceImpl.java diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfig.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfig.java index 1e8b5db7..356b9c7e 100755 --- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfig.java +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfig.java @@ -17,7 +17,7 @@ package com.pig4cloud.pig.auth.config; import com.pig4cloud.pig.auth.converter.CustomAccessTokenConverter; -import com.pig4cloud.pig.auth.grant.ResourceOwnerPhoneTokenGranter; +import com.pig4cloud.pig.common.security.grant.ResourceOwnerPhoneTokenGranter; import com.pig4cloud.pig.common.core.constant.CacheConstants; import com.pig4cloud.pig.common.core.constant.SecurityConstants; import com.pig4cloud.pig.common.security.component.PigWebResponseExceptionTranslator; @@ -92,8 +92,9 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap // 获取默认授权类型 TokenGranter tokenGranter = endpoints.getTokenGranter(); ArrayList tokenGranters = new ArrayList<>(Arrays.asList(tokenGranter)); - ResourceOwnerPhoneTokenGranter resourceOwnerPhoneTokenGranter = new ResourceOwnerPhoneTokenGranter(authenticationManager, - endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()); + ResourceOwnerPhoneTokenGranter resourceOwnerPhoneTokenGranter = new ResourceOwnerPhoneTokenGranter( + authenticationManager, endpoints.getTokenServices(), endpoints.getClientDetailsService(), + endpoints.getOAuth2RequestFactory()); tokenGranters.add(resourceOwnerPhoneTokenGranter); CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(tokenGranters); endpoints.tokenGranter(compositeTokenGranter); diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfigurer.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfigurer.java index f8a9c94d..bcb6d41c 100755 --- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfigurer.java +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfigurer.java @@ -16,7 +16,7 @@ package com.pig4cloud.pig.auth.config; -import com.pig4cloud.pig.auth.grant.PhoneAuthenticationProvider; +import com.pig4cloud.pig.common.security.grant.PhoneAuthenticationProvider; import com.pig4cloud.pig.common.security.handler.FormAuthenticationFailureHandler; import com.pig4cloud.pig.common.security.handler.SsoLogoutSuccessHandler; import lombok.AllArgsConstructor; @@ -50,9 +50,8 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override @SneakyThrows protected void configure(HttpSecurity http) { - http.authenticationProvider(phoneAuthenticationProvider()) - .formLogin().loginPage("/token/login").loginProcessingUrl("/token/form") - .failureHandler(authenticationFailureHandler()).and().logout() + http.authenticationProvider(phoneAuthenticationProvider()).formLogin().loginPage("/token/login") + .loginProcessingUrl("/token/form").failureHandler(authenticationFailureHandler()).and().logout() .logoutSuccessHandler(logoutSuccessHandler()).deleteCookies("JSESSIONID").invalidateHttpSession(true) .and().authorizeRequests().antMatchers("/token/**", "/actuator/**", "/mobile/**").permitAll() .anyRequest().authenticated().and().csrf().disable(); @@ -87,7 +86,6 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { /** * 支持SSO 退出 - * * @return LogoutSuccessHandler */ @Bean @@ -98,7 +96,6 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { /** * https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released#password-storage-updated * Encoded password does not look like BCrypt - * * @return PasswordEncoder */ @Bean diff --git a/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/SecurityConstants.java b/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/SecurityConstants.java index 63486d74..b15f91e4 100755 --- a/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/SecurityConstants.java +++ b/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/SecurityConstants.java @@ -56,6 +56,10 @@ public interface SecurityConstants { * grant_type */ String REFRESH_TOKEN = "refresh_token"; + + /** + * 手机号登录 + */ String PHONE = "phone"; /** @@ -120,4 +124,9 @@ public interface SecurityConstants { */ long CODE_TIME = 60; + /** + * 验证码长度 + */ + String CODE_SIZE = "6"; + } diff --git a/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/enums/LoginTypeEnum.java b/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/enums/LoginTypeEnum.java index 85bd2ecf..ef4b810b 100644 --- a/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/enums/LoginTypeEnum.java +++ b/pig-common/pig-common-core/src/main/java/com/pig4cloud/pig/common/core/constant/enums/LoginTypeEnum.java @@ -33,14 +33,9 @@ public enum LoginTypeEnum { PWD("PWD", "账号密码登录"), /** - * QQ登录 + * 验证码登录 */ - QQ("QQ", "QQ登录"), - - /** - * 微信登录 - */ - WECHAT("WX", "微信登录"); + SMS("SMS", "验证码登录"); /** * 类型 diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationProvider.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/grant/PhoneAuthenticationProvider.java similarity index 51% rename from pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationProvider.java rename to pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/grant/PhoneAuthenticationProvider.java index efe873de..6359b11d 100644 --- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationProvider.java +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/grant/PhoneAuthenticationProvider.java @@ -1,14 +1,18 @@ -package com.pig4cloud.pig.auth.grant; +package com.pig4cloud.pig.common.security.grant; +import cn.hutool.core.util.StrUtil; import com.pig4cloud.pig.common.security.service.PigUserDetailsServiceImpl; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.BeanCreationException; -import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; /** @@ -16,13 +20,32 @@ import org.springframework.security.crypto.password.PasswordEncoder; * @since 2021-09-14 */ @Slf4j -public class PhoneAuthenticationProvider implements AuthenticationProvider { +public class PhoneAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { @Setter private UserDetailsService userDetailsService; + @Setter private PasswordEncoder passwordEncoder; + /** + * 校验 请求信息userDetails + * @param userDetails 用户信息 + * @param authentication 认证信息 + * @throws AuthenticationException + */ + @Override + protected void additionalAuthenticationChecks(UserDetails userDetails, + UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { + + if (authentication.getCredentials() == null) { + this.logger.debug("Failed to authenticate since no credentials provided"); + throw new BadCredentialsException(this.messages + .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); + } + + } + @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { @@ -34,29 +57,26 @@ public class PhoneAuthenticationProvider implements AuthenticationProvider { // 手机号 String phone = authentication.getName(); - // 验证码/密码 - // 验证码模式 自己去实现验证码检验 - // 这里的code指的是密码 - String code = authentication.getCredentials().toString(); - - UserDetails userDetails = ((PigUserDetailsServiceImpl) userDetailsService).loadUserByPhone(phone); - - String password = userDetails.getPassword(); - - boolean matches = passwordEncoder.matches(code, password); - if (!matches) { - throw new BeanCreationException("Bad credentials"); + if (StrUtil.equals(phone, "17034642999")) { + throw new UsernameNotFoundException(phone); } + String code = authentication.getCredentials().toString(); + UserDetails userDetails = ((PigUserDetailsServiceImpl) userDetailsService).loadUserByPhone(phone); PhoneAuthenticationToken token = new PhoneAuthenticationToken(userDetails); - token.setDetails(authentication.getDetails()); - return token; } + @Override + protected UserDetails retrieveUser(String phone, UsernamePasswordAuthenticationToken authentication) + throws AuthenticationException { + return null; + } + @Override public boolean supports(Class authentication) { return authentication.isAssignableFrom(PhoneAuthenticationToken.class); } -} \ No newline at end of file + +} diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationToken.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/grant/PhoneAuthenticationToken.java similarity index 91% rename from pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationToken.java rename to pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/grant/PhoneAuthenticationToken.java index db0456a2..44260059 100644 --- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/PhoneAuthenticationToken.java +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/grant/PhoneAuthenticationToken.java @@ -1,4 +1,4 @@ -package com.pig4cloud.pig.auth.grant; +package com.pig4cloud.pig.common.security.grant; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.authority.AuthorityUtils; @@ -10,7 +10,7 @@ import org.springframework.security.core.userdetails.UserDetails; */ public class PhoneAuthenticationToken extends AbstractAuthenticationToken { - private Object principal; + private final Object principal; // 验证码/密码 private String code; diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/ResourceOwnerPhoneTokenGranter.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/grant/ResourceOwnerPhoneTokenGranter.java similarity index 79% rename from pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/ResourceOwnerPhoneTokenGranter.java rename to pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/grant/ResourceOwnerPhoneTokenGranter.java index b69c13bc..d396b1ca 100644 --- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/grant/ResourceOwnerPhoneTokenGranter.java +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/grant/ResourceOwnerPhoneTokenGranter.java @@ -1,4 +1,4 @@ -package com.pig4cloud.pig.auth.grant; +package com.pig4cloud.pig.common.security.grant; import cn.hutool.core.util.StrUtil; import org.springframework.security.authentication.AbstractAuthenticationToken; @@ -27,16 +27,14 @@ public class ResourceOwnerPhoneTokenGranter extends AbstractTokenGranter { private final AuthenticationManager authenticationManager; public ResourceOwnerPhoneTokenGranter(AuthenticationManager authenticationManager, - AuthorizationServerTokenServices tokenServices, - ClientDetailsService clientDetailsService, - OAuth2RequestFactory requestFactory) { + AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, + OAuth2RequestFactory requestFactory) { this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE); } protected ResourceOwnerPhoneTokenGranter(AuthenticationManager authenticationManager, - AuthorizationServerTokenServices tokenServices, - ClientDetailsService clientDetailsService, - OAuth2RequestFactory requestFactory, String grantType) { + AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, + OAuth2RequestFactory requestFactory, String grantType) { super(tokenServices, clientDetailsService, requestFactory, grantType); this.authenticationManager = authenticationManager; } @@ -62,13 +60,13 @@ public class ResourceOwnerPhoneTokenGranter extends AbstractTokenGranter { ((AbstractAuthenticationToken) userAuth).setDetails(parameters); try { userAuth = authenticationManager.authenticate(userAuth); - } catch (AccountStatusException ase) { - //covers expired, locked, disabled cases (mentioned in section 5.2, draft 31) - throw new InvalidGrantException(ase.getMessage()); - } catch (BadCredentialsException e) { - // If the phone/code are wrong the spec says we should send 400/invalid grant - throw new InvalidGrantException(e.getMessage()); } + catch (AccountStatusException | BadCredentialsException ase) { + // covers expired, locked, disabled cases (mentioned in section 5.2, draft 31) + throw new InvalidGrantException(ase.getMessage()); + } + // If the phone/code are wrong the spec says we should send 400/invalid grant + if (userAuth == null || !userAuth.isAuthenticated()) { throw new InvalidGrantException("Could not authenticate user: " + phone); } @@ -76,4 +74,5 @@ public class ResourceOwnerPhoneTokenGranter extends AbstractTokenGranter { OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest); return new OAuth2Authentication(storedOAuth2Request, userAuth); } + } diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java index 18f2b189..198196ab 100755 --- a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigUserDetailsServiceImpl.java @@ -62,7 +62,6 @@ public class PigUserDetailsServiceImpl implements UserDetailsService { /** * 用户密码登录 - * * @param username 用户名 * @return */ @@ -84,7 +83,6 @@ public class PigUserDetailsServiceImpl implements UserDetailsService { /** * 手机号码登录 - * * @param phone 手机号码 * @return 用户信息 */ @@ -96,7 +94,6 @@ public class PigUserDetailsServiceImpl implements UserDetailsService { /** * 构建userdetails - * * @param result 用户信息 * @return UserDetails */ diff --git a/pig-gateway/src/main/java/com/pig4cloud/pig/gateway/filter/ValidateCodeGatewayFilter.java b/pig-gateway/src/main/java/com/pig4cloud/pig/gateway/filter/ValidateCodeGatewayFilter.java index 78a1c630..8c2d742f 100644 --- a/pig-gateway/src/main/java/com/pig4cloud/pig/gateway/filter/ValidateCodeGatewayFilter.java +++ b/pig-gateway/src/main/java/com/pig4cloud/pig/gateway/filter/ValidateCodeGatewayFilter.java @@ -70,7 +70,8 @@ public class ValidateCodeGatewayFilter extends AbstractGatewayFilterFactory infoByPhone(@PathVariable("phone") String phone, @RequestHeader(SecurityConstants.FROM) String from); - /** - * 通过社交账号查询用户、角色信息 - * - * @param inStr appid@code - * @return - */ - @GetMapping("/social/info/{inStr}") - R social(@PathVariable("inStr") String inStr); - /** * 根据部门id,查询对应的用户 id 集合 - * * @param deptIds 部门id 集合 - * @param from 调用标志 + * @param from 调用标志 * @return 用户 id 集合 */ @GetMapping("/user/ids") R> listUserIdByDeptIds(@RequestParam("deptIds") Set deptIds, - @RequestHeader(SecurityConstants.FROM) String from); + @RequestHeader(SecurityConstants.FROM) String from); } diff --git a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java index f11dab68..23af9e5e 100755 --- a/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java +++ b/pig-upms/pig-upms-api/src/main/java/com/pig4cloud/pig/admin/api/feign/fallback/RemoteUserServiceFallbackImpl.java @@ -39,9 +39,8 @@ public class RemoteUserServiceFallbackImpl implements RemoteUserService { /** * 通过用户名查询用户、角色信息 - * * @param username 用户名 - * @param from 内外标志 + * @param from 内外标志 * @return R */ @Override @@ -52,9 +51,8 @@ public class RemoteUserServiceFallbackImpl implements RemoteUserService { /** * 通过手机号码查询用户、角色信息 - * * @param phone 手机号码 - * @param from 调用标志 + * @param from 调用标志 * @return R */ @Override @@ -63,18 +61,6 @@ public class RemoteUserServiceFallbackImpl implements RemoteUserService { return null; } - /** - * 通过社交账号查询用户、角色信息 - * - * @param inStr appid@code - * @return - */ - @Override - public R social(String inStr) { - log.error("feign 查询用户信息失败:{}", inStr, cause); - return null; - } - @Override public R> listUserIdByDeptIds(Set deptIds, String from) { log.error("feign 根据部门ids查询用户Id集合失败:{}", deptIds, cause); diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/MobileController.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/MobileController.java new file mode 100644 index 00000000..69ddebd3 --- /dev/null +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/MobileController.java @@ -0,0 +1,51 @@ +package com.pig4cloud.pig.admin.controller; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.pig4cloud.pig.admin.api.entity.SysUser; +import com.pig4cloud.pig.admin.service.MobileService; +import com.pig4cloud.pig.admin.service.SysUserService; +import com.pig4cloud.pig.common.core.util.R; +import com.pig4cloud.pig.common.security.annotation.Inner; +import io.swagger.annotations.Api; +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author lengleng + * @date 2021/9/16 移动端登录 + */ +@RestController +@AllArgsConstructor +@RequestMapping("/mobile") +@Api(value = "mobile", tags = "手机管理模块") +public class MobileController { + + private final MobileService mobileService; + + private final SysUserService userService; + + @Inner(value = false) + @GetMapping("/{mobile}") + public R sendSmsCode(@PathVariable String mobile) { + return mobileService.sendSmsCode(mobile); + } + + /** + * 获取指定用户全部信息 + * @param phone 手机号 + * @return 用户信息 + */ + @Inner + @GetMapping("/{phone}") + public R infoByPhone(@PathVariable String phone) { + SysUser user = userService.getOne(Wrappers.query().lambda().eq(SysUser::getPhone, phone)); + if (user == null) { + return R.failed(String.format("用户信息为空 %s", phone)); + } + return R.ok(userService.getUserInfo(user)); + } + +} diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/UserController.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/UserController.java index bf00dcbe..ae191416 100644 --- a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/UserController.java +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/controller/UserController.java @@ -94,20 +94,6 @@ public class UserController { return R.ok(userService.getUserInfo(user)); } - /** - * 获取指定用户全部信息 - * @return 用户信息 - */ - @Inner - @GetMapping("/infoByPhone/{phone}") - public R infoByPhone(@PathVariable String phone) { - SysUser user = userService.getOne(Wrappers.query().lambda().eq(SysUser::getPhone, phone)); - if (user == null) { - return R.failed(String.format("用户信息为空 %s", phone)); - } - return R.ok(userService.getUserInfo(user)); - } - /** * 根据部门id,查询对应的用户 id 集合 * @param deptIds 部门id 集合 diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/MobileService.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/MobileService.java new file mode 100644 index 00000000..892b8a12 --- /dev/null +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/MobileService.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.pig.admin.service; + +import com.pig4cloud.pig.common.core.util.R; + +/** + * @author lengleng + * @date 2018/11/14 + */ +public interface MobileService { + + /** + * 发送手机验证码 + * @param mobile mobile + * @return code + */ + R sendSmsCode(String mobile); + +} diff --git a/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/MobileServiceImpl.java b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/MobileServiceImpl.java new file mode 100644 index 00000000..26495949 --- /dev/null +++ b/pig-upms/pig-upms-biz/src/main/java/com/pig4cloud/pig/admin/service/MobileServiceImpl.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.pig.admin.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.RandomUtil; +import com.baomidou.mybatisplus.core.toolkit.StringPool; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.pig4cloud.pig.admin.api.entity.SysUser; +import com.pig4cloud.pig.admin.mapper.SysUserMapper; +import com.pig4cloud.pig.common.core.constant.CacheConstants; +import com.pig4cloud.pig.common.core.constant.SecurityConstants; +import com.pig4cloud.pig.common.core.constant.enums.LoginTypeEnum; +import com.pig4cloud.pig.common.core.util.R; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * @author lengleng + * @date 2018/11/14 + *

+ * 手机登录相关业务实现 + */ +@Slf4j +@Service +@AllArgsConstructor +public class MobileServiceImpl implements MobileService { + + private final RedisTemplate redisTemplate; + + private final SysUserMapper userMapper; + + /** + * 发送手机验证码 TODO: 调用短信网关发送验证码,测试返回前端 + * @param mobile mobile + * @return code + */ + @Override + public R sendSmsCode(String mobile) { + List userList = userMapper + .selectList(Wrappers.query().lambda().eq(SysUser::getPhone, mobile)); + + if (CollUtil.isEmpty(userList)) { + log.info("手机号未注册:{}", mobile); + return R.ok(Boolean.FALSE, "手机号未注册"); + } + + Object codeObj = redisTemplate.opsForValue() + .get(CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile); + + if (codeObj != null) { + log.info("手机号验证码未过期:{},{}", mobile, codeObj); + return R.ok(Boolean.FALSE, "验证码发送过频繁"); + } + + String code = RandomUtil.randomNumbers(Integer.parseInt(SecurityConstants.CODE_SIZE)); + log.debug("手机号生成验证码成功:{},{}", mobile, code); + redisTemplate.opsForValue().set( + CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile, code, + SecurityConstants.CODE_TIME, TimeUnit.SECONDS); + return R.ok(Boolean.TRUE, code); + } + +}