diff --git a/pom.xml b/pom.xml index 929117de614be23a737d8fde5d5f44dc653fcdf8..6021fe54366f71a391a609b49485fbdd4e538d55 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,15 @@ along with this program. If not, see .--> neatlogic-framework 0.4.0.0-SNAPSHOT + + + org.apache.maven.plugins + maven-compiler-plugin + + none + + + src/main/java @@ -43,4 +52,4 @@ along with this program. If not, see .--> - \ No newline at end of file + diff --git a/src/main/java/neatlogic/framework/annotationprocessor/NeatLogicApi.java b/src/main/java/neatlogic/framework/annotationprocessor/NeatLogicApi.java new file mode 100644 index 0000000000000000000000000000000000000000..a24609ad4017d12dd492013ee63e9a0a9e760170 --- /dev/null +++ b/src/main/java/neatlogic/framework/annotationprocessor/NeatLogicApi.java @@ -0,0 +1,10 @@ +package neatlogic.framework.annotationprocessor; + +import java.lang.annotation.*; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface NeatLogicApi { + String value() default ""; +} diff --git a/src/main/java/neatlogic/framework/annotationprocessor/NeatLogicApiAnnotationProcessor.java b/src/main/java/neatlogic/framework/annotationprocessor/NeatLogicApiAnnotationProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..3ec98b4ad70620dace2a7b5737975e008556a364 --- /dev/null +++ b/src/main/java/neatlogic/framework/annotationprocessor/NeatLogicApiAnnotationProcessor.java @@ -0,0 +1,130 @@ +package neatlogic.framework.annotationprocessor; + +import neatlogic.framework.restful.core.IApiComponent; +import neatlogic.framework.restful.core.IBinaryStreamApiComponent; +import neatlogic.framework.restful.core.IJsonStreamApiComponent; +import neatlogic.framework.restful.core.IRawApiComponent; +import org.apache.commons.collections4.CollectionUtils; + +import javax.annotation.processing.*; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import javax.tools.Diagnostic; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +@SupportedAnnotationTypes("neatlogic.framework.annotationprocessor.NeatLogicApi") +@SupportedSourceVersion(SourceVersion.RELEASE_17) +public class NeatLogicApiAnnotationProcessor extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (annotations.isEmpty()) { + return false; + } + Elements elementUtils = processingEnv.getElementUtils(); + Types typeUtils = processingEnv.getTypeUtils(); + TypeElement componentTypeElement = processingEnv.getElementUtils().getTypeElement("org.springframework.stereotype.Component"); + TypeElement serviceTypeElement = processingEnv.getElementUtils().getTypeElement("org.springframework.stereotype.Service"); + TypeElement repositoryTypeElement = processingEnv.getElementUtils().getTypeElement("org.springframework.stereotype.Repository"); + TypeElement controllerTypeElement = processingEnv.getElementUtils().getTypeElement("org.springframework.stereotype.Controller"); + TypeElement authActionTypeElement = processingEnv.getElementUtils().getTypeElement("neatlogic.framework.auth.core.AuthAction"); + TypeElement authActionsTypeElement = processingEnv.getElementUtils().getTypeElement("neatlogic.framework.auth.core.AuthActions"); + TypeElement neatLogicApiTypeElement = elementUtils.getTypeElement("neatlogic.framework.annotationprocessor.NeatLogicApi"); + Set neatLogicApiElements = roundEnv.getElementsAnnotatedWith(neatLogicApiTypeElement); + Set neatLogicApiClasses = ElementFilter.typesIn(neatLogicApiElements); + if (componentTypeElement != null + && serviceTypeElement != null + && repositoryTypeElement != null + && controllerTypeElement != null + && authActionTypeElement != null + && authActionsTypeElement != null + && CollectionUtils.isNotEmpty(neatLogicApiClasses) + ) { + TypeElement apiComponentTypeElement = elementUtils.getTypeElement(IApiComponent.class.getName()); + TypeElement binaryStreamApiComponentTypeElement = elementUtils.getTypeElement(IBinaryStreamApiComponent.class.getName()); + TypeElement jsonStreamApiComponentTypeElement = elementUtils.getTypeElement(IJsonStreamApiComponent.class.getName()); + TypeElement rawApiComponentTypeElement = elementUtils.getTypeElement(IRawApiComponent.class.getName()); + TypeMirror apiComponentTypeMirror = apiComponentTypeElement.asType(); + TypeMirror binaryStreamApiComponentTypeMirror = binaryStreamApiComponentTypeElement.asType(); + TypeMirror jsonStreamApiComponentTypeMirror = jsonStreamApiComponentTypeElement.asType(); + TypeMirror rawApiComponentTypeMirror = rawApiComponentTypeElement.asType(); + for (TypeElement neatLogicApiClass : neatLogicApiClasses) { + if (implementsInterface(neatLogicApiClass, apiComponentTypeMirror, typeUtils) + || implementsInterface(neatLogicApiClass, binaryStreamApiComponentTypeMirror, typeUtils) + || implementsInterface(neatLogicApiClass, jsonStreamApiComponentTypeMirror, typeUtils) + || implementsInterface(neatLogicApiClass, rawApiComponentTypeMirror, typeUtils) + ) { + boolean isBean = false; + List annotationMirrors = neatLogicApiClass.getAnnotationMirrors(); + for (AnnotationMirror annotationMirror : annotationMirrors) { + Element element = annotationMirror.getAnnotationType().asElement(); + if (Objects.equals(element, componentTypeElement) + || Objects.equals(element, serviceTypeElement) + || Objects.equals(element, repositoryTypeElement) + || Objects.equals(element, controllerTypeElement)) + { + isBean = true; + break; + } + } + if (isBean) { + boolean hasAuthAction = false; + for (AnnotationMirror annotationMirror : annotationMirrors) { + Element element = annotationMirror.getAnnotationType().asElement(); + if (Objects.equals(element, authActionTypeElement) || Objects.equals(element, authActionsTypeElement)) { + hasAuthAction = true; + break; + } + } + if (!hasAuthAction) { + processingEnv.getMessager().printMessage( + Diagnostic.Kind.ERROR, + neatLogicApiClass.getQualifiedName() + "接口类需要加上@AuthAction注解进行权限控制, 如果未创建权限类, 可以先临时加上@AuthAction(action = NoAuth.class)使得编译通过", + neatLogicApiClass + ); + } + } + } + } + } + + return true; + } + + // 检查元素是否实现了指定的接口 + private boolean implementsInterface(TypeElement typeElement, TypeMirror interfaceType, Types typeUtils) { + // 检查直接实现的接口 + for (TypeMirror implementedInterface : typeElement.getInterfaces()) { + if (typeUtils.isSameType(implementedInterface, interfaceType)) { + return true; + } + + // 检查接口继承关系 + if (implementedInterface.getKind() == TypeKind.DECLARED) { + TypeElement interfaceElement = (TypeElement) ((DeclaredType) implementedInterface).asElement(); + if (implementsInterface(interfaceElement, interfaceType, typeUtils)) { + return true; + } + } + } + + // 检查父类的接口实现 + TypeMirror superClass = typeElement.getSuperclass(); + if (superClass.getKind() != TypeKind.NONE) { + TypeElement superClassElement = (TypeElement) ((DeclaredType) superClass).asElement(); + return implementsInterface(superClassElement, interfaceType, typeUtils); + } + + return false; + } +} diff --git a/src/main/java/neatlogic/framework/auth/core/AuthActionChecker.java b/src/main/java/neatlogic/framework/auth/core/AuthActionChecker.java index 6844701a0325d263ba31fb2eee5f387fb29ca40f..cc1e88378783ada856e30ece3c5d5173ba053fc7 100644 --- a/src/main/java/neatlogic/framework/auth/core/AuthActionChecker.java +++ b/src/main/java/neatlogic/framework/auth/core/AuthActionChecker.java @@ -17,6 +17,7 @@ package neatlogic.framework.auth.core; import neatlogic.framework.asynchronization.threadlocal.UserContext; import neatlogic.framework.auth.init.MaintenanceMode; +import neatlogic.framework.auth.label.NoAuth; import neatlogic.framework.common.RootComponent; import neatlogic.framework.common.config.Config; import neatlogic.framework.common.constvalue.systemuser.SystemUserFactory; @@ -130,6 +131,9 @@ public class AuthActionChecker { if (CollectionUtils.isEmpty(actionList)) { return false; } + if (actionList.contains(NoAuth.class.getSimpleName())) { + return true; + } //判断从数据库查询的用户权限是否满足 AuthenticationInfoVo authenticationInfoVo; if (UserContext.get() != null) { diff --git a/src/main/java/neatlogic/framework/auth/core/AuthFactory.java b/src/main/java/neatlogic/framework/auth/core/AuthFactory.java index 3ac00e3879a20700017798a946914413e564a201..713a6769c0f1e8e4d1bdbe8111b4f02bb208aa3c 100644 --- a/src/main/java/neatlogic/framework/auth/core/AuthFactory.java +++ b/src/main/java/neatlogic/framework/auth/core/AuthFactory.java @@ -15,6 +15,7 @@ along with this program. If not, see .*/ package neatlogic.framework.auth.core; +import neatlogic.framework.auth.label.NoAuth; import neatlogic.framework.common.util.ModuleUtil; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.logging.Log; @@ -37,7 +38,7 @@ public class AuthFactory { for (Class c : authClass) { try { //排除抽象类 - if (!Modifier.isAbstract(c.getModifiers())) { + if (!Modifier.isAbstract(c.getModifiers()) && c != NoAuth.class) { AuthBase authIns = c.newInstance(); if (ModuleUtil.getModuleGroup(authIns.getAuthGroup()) == null || (authIns instanceof AuthCSBase && ModuleUtil.isModuleInvalidated(authIns.getAuthModule()))) { continue; diff --git a/src/main/java/neatlogic/framework/restful/core/ApiValidateAndHelpBase.java b/src/main/java/neatlogic/framework/restful/core/ApiValidateAndHelpBase.java index 863e101cb368a7f29fa28547613b11c2cd0c42b0..aee9cee9a2ebd3f356f7ae509a9640dd16ac8366 100644 --- a/src/main/java/neatlogic/framework/restful/core/ApiValidateAndHelpBase.java +++ b/src/main/java/neatlogic/framework/restful/core/ApiValidateAndHelpBase.java @@ -19,6 +19,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; +import neatlogic.framework.annotationprocessor.NeatLogicApi; import neatlogic.framework.asynchronization.threadlocal.TenantContext; import neatlogic.framework.asynchronization.threadlocal.UserContext; import neatlogic.framework.auth.core.AuthAction; @@ -63,6 +64,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +@NeatLogicApi public class ApiValidateAndHelpBase { private static final Logger logger = LoggerFactory.getLogger(ApiValidateAndHelpBase.class); @@ -245,10 +247,6 @@ public class ApiValidateAndHelpBase { private boolean isApiAuth(Class apiClass, List authNameList, AuthAction[] actions) { boolean isAuth = false; for (AuthAction action : actions) { - if (action.action() == NoAuth.class) { - isAuth = true; - break; - } if (StringUtils.isNotBlank(action.action().getSimpleName())) { String actionName = action.action().getSimpleName(); // 判断用户角色是否拥有接口权限 diff --git a/src/main/java/neatlogic/framework/restful/core/privateapi/PrivateApiComponentFactory.java b/src/main/java/neatlogic/framework/restful/core/privateapi/PrivateApiComponentFactory.java index 16abeaed2836985e675f71bf682ec3c708a77a9c..65178450d377946ced8469698c6c87a993f536b7 100644 --- a/src/main/java/neatlogic/framework/restful/core/privateapi/PrivateApiComponentFactory.java +++ b/src/main/java/neatlogic/framework/restful/core/privateapi/PrivateApiComponentFactory.java @@ -429,18 +429,19 @@ public class PrivateApiComponentFactory extends ModuleInitializedListenerBase { logger.warn(clazz.getName() + "接口没有OperationType注解"); } - //System.out.println(clazz.getSimpleName()); +// System.out.println(clazz.getSimpleName()); //跳过匿名接口 - if (component instanceof IApiComponent && ((IApiComponent) component).supportAnonymousAccess().isSupportAnonymousAccess()) { - return; - } - if (!Objects.equals(context.getId(), "framework") && !Objects.equals(context.getId(), "tenant")) { +// if (component instanceof IApiComponent && ((IApiComponent) component).supportAnonymousAccess().isSupportAnonymousAccess()) { +// return; +// } +// if (!Objects.equals(context.getId(), "framework") && !Objects.equals(context.getId(), "tenant")) { AuthAction authAction = clazz.getAnnotation(AuthAction.class); AuthActions authActions = clazz.getAnnotation(AuthActions.class); if (authAction == null && authActions == null) { - logger.warn(clazz.getName() + "接口没有AuthAction注解"); + System.err.println(clazz.getName() + "接口类需要加上@AuthAction注解进行权限控制, 如果未创建权限类, 可以先临时加上@AuthAction(action = NoAuth.class)使得应用服务正常启动"); + System.exit(1); } - } +// } } } diff --git a/src/main/java/neatlogic/module/framework/restful/api/AuthSearchApi.java b/src/main/java/neatlogic/module/framework/restful/api/AuthSearchApi.java index 43df14be50c4b6afcb98cf3dc217ccdcd1e170c1..0a2ad1c3890bf94fc6a2420df97678af456265b3 100755 --- a/src/main/java/neatlogic/module/framework/restful/api/AuthSearchApi.java +++ b/src/main/java/neatlogic/module/framework/restful/api/AuthSearchApi.java @@ -17,8 +17,10 @@ package neatlogic.module.framework.restful.api; import com.alibaba.fastjson.JSONObject; import neatlogic.framework.asynchronization.threadlocal.TenantContext; +import neatlogic.framework.auth.core.AuthAction; import neatlogic.framework.auth.core.AuthBase; import neatlogic.framework.auth.core.AuthFactory; +import neatlogic.framework.auth.label.NoAuth; import neatlogic.framework.common.constvalue.ApiParamType; import neatlogic.framework.common.util.ModuleUtil; import neatlogic.framework.dto.AuthGroupVo; @@ -33,7 +35,7 @@ import java.util.List; import java.util.Map; @Service - +@AuthAction(action = NoAuth.class) @OperationType(type = OperationTypeEnum.SEARCH) public class AuthSearchApi extends PrivateApiComponentBase { diff --git a/src/main/java/neatlogic/module/framework/restful/api/LogoutApi.java b/src/main/java/neatlogic/module/framework/restful/api/LogoutApi.java index 78b62502333a8e3cf2b22a9ac8c693c9c27f116a..df2ba33bd525ba93bae5c0140f80793c75c5b78f 100755 --- a/src/main/java/neatlogic/module/framework/restful/api/LogoutApi.java +++ b/src/main/java/neatlogic/module/framework/restful/api/LogoutApi.java @@ -16,6 +16,8 @@ along with this program. If not, see .*/ package neatlogic.module.framework.restful.api; import com.alibaba.fastjson.JSONObject; +import neatlogic.framework.auth.core.AuthAction; +import neatlogic.framework.auth.label.NoAuth; import neatlogic.framework.common.config.Config; import neatlogic.framework.exception.login.LoginAuthNotFoundException; import neatlogic.framework.filter.core.ILoginAuthHandler; @@ -30,6 +32,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @Service +@AuthAction(action = NoAuth.class) @OperationType(type = OperationTypeEnum.OPERATE) public class LogoutApi extends PrivateApiComponentBase { diff --git a/src/main/java/neatlogic/module/framework/restful/api/ModuleListApi.java b/src/main/java/neatlogic/module/framework/restful/api/ModuleListApi.java index a6196cb7ef23a04edb1cef32d3059a6f4929796b..688f1af7cf7476bb734d11b4422d5790ba71b259 100644 --- a/src/main/java/neatlogic/module/framework/restful/api/ModuleListApi.java +++ b/src/main/java/neatlogic/module/framework/restful/api/ModuleListApi.java @@ -19,6 +19,8 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import neatlogic.framework.asynchronization.threadlocal.TenantContext; import neatlogic.framework.asynchronization.threadlocal.UserContext; +import neatlogic.framework.auth.core.AuthAction; +import neatlogic.framework.auth.label.NoAuth; import neatlogic.framework.common.constvalue.ApiParamType; import neatlogic.framework.dao.mapper.UserMapper; import neatlogic.framework.dto.AuthenticationInfoVo; @@ -37,6 +39,7 @@ import java.util.List; import java.util.Set; @Service +@AuthAction(action = NoAuth.class) @OperationType(type = OperationTypeEnum.SEARCH) public class ModuleListApi extends PrivateApiComponentBase { @Autowired