diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java index 70d1f3e0e2..89bb1b7980 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java @@ -43,6 +43,7 @@ import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.imenu.UIMenuItem; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.authority.JTemplateAuthorityChecker; import com.fr.design.mainframe.chart.info.ChartInfoCollector; import com.fr.design.mainframe.check.CheckButton; import com.fr.design.mainframe.template.info.TemplateProcessInfo; @@ -247,6 +248,7 @@ public abstract class JTemplate> } } } + private void stopListenThemeConfig() { if (themeConfigChangeListener != null) { TemplateThemeConfig config = getUsingTemplateThemeConfig(); @@ -269,7 +271,7 @@ public abstract class JTemplate> public void fireTabChange() { // do nothing } - + protected void addPane(PropertyItemPaneProvider provider) { // do nothing } @@ -1404,7 +1406,7 @@ public abstract class JTemplate> * @return 按钮组 */ public UIButton[] createExtraButtons() { - UIButton[] uiButtons = new UIButton[] { + UIButton[] uiButtons = new UIButton[]{ (UIButton) new CompileAction().createToolBarComponent() }; Set providers = ExtraDesignClassManager.getInstance().getArray(DesignerFrameUpButtonProvider.XML_TAG); @@ -1549,13 +1551,19 @@ public abstract class JTemplate> } private boolean saveRealFile() throws Exception { - FILE editingFILE = this.getEditingFILE(); - if (editingFILE == null || editingFILE instanceof MemFILE) { + JTemplateAuthorityChecker jTemplateAuthorityChecker = new JTemplateAuthorityChecker(this); + if (jTemplateAuthorityChecker.isAuthority()) { + FILE editingFILE = this.getEditingFILE(); + if (editingFILE == null || editingFILE instanceof MemFILE) { + return false; + } + this.getTarget().export(TemplateResourceManager.getResource().saveTemplate(editingFILE)); + this.editingFILE = editingFILE; + return true; + } else { + jTemplateAuthorityChecker.showAuthorityFailPromptDialog(); return false; } - this.getTarget().export(TemplateResourceManager.getResource().saveTemplate(editingFILE)); - this.editingFILE = editingFILE; - return true; } private CallbackSaveWorker saveAs(boolean showLoc) { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/authority/DSColumnAuthorityChecker.java b/designer-base/src/main/java/com/fr/design/mainframe/authority/DSColumnAuthorityChecker.java new file mode 100644 index 0000000000..fdab6ea2a2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/authority/DSColumnAuthorityChecker.java @@ -0,0 +1,20 @@ +package com.fr.design.mainframe.authority; + +import com.fr.report.cell.cellattr.core.group.DSColumn; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class DSColumnAuthorityChecker extends ElementAuthorityChecker { + + @Override + @Nullable + Set getNoAuthDatasetNames(DSColumn dsColumn, Set authDatasetNames) { + if (!authDatasetNames.contains(dsColumn.getDSName())) { + return new HashSet<>(Arrays.asList(dsColumn.getDSName())); + } + return null; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/authority/ElementAuthorityChecker.java b/designer-base/src/main/java/com/fr/design/mainframe/authority/ElementAuthorityChecker.java new file mode 100644 index 0000000000..67d0f1da36 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/authority/ElementAuthorityChecker.java @@ -0,0 +1,45 @@ +package com.fr.design.mainframe.authority; + +import org.jetbrains.annotations.Nullable; +import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; + +import java.lang.reflect.Type; +import java.util.Set; + + +public abstract class ElementAuthorityChecker { + + + /** + * @Description 获取越权的数据连接 + * @param: t 待检查的对象 + * @param: authConnectionNames 有权限的数据连接名 + * @return 如果有返回名称,没有返回null + */ + @Nullable + Set getNoAuthConnectionNames(T t, Set authConnectionNames) { + return null; + } + + + /** + * @Description 获取越权的服务器数据集 + * @param: t 待检查的对象 + * @param: authDatasetNames 有权限的服务器数据集名 + * @return 如果有返回名称,没有返回null + */ + @Nullable + Set getNoAuthDatasetNames(T t, Set authDatasetNames) { + return null; + } + + /** + * @Description 要检查对象的className + * @return className + */ + String getCheckClassName() { + ParameterizedTypeImpl parameterizedType = (ParameterizedTypeImpl) this.getClass().getGenericSuperclass(); + Type type = parameterizedType.getActualTypeArguments()[0]; + return type.getTypeName(); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/authority/FormulaAuthorityChecker.java b/designer-base/src/main/java/com/fr/design/mainframe/authority/FormulaAuthorityChecker.java new file mode 100644 index 0000000000..d108c18d41 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/authority/FormulaAuthorityChecker.java @@ -0,0 +1,27 @@ +package com.fr.design.mainframe.authority; + +import com.fr.base.Formula; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class FormulaAuthorityChecker extends ElementAuthorityChecker { + private static final Pattern FORMULA_PATTERN = Pattern.compile("^=SQL\\(\"(.+?)\","); + + @Override + @Nullable + public Set getNoAuthConnectionNames(Formula formula, Set authConnectionNames) { + String content = formula.getContent(); + Matcher matcher = FORMULA_PATTERN.matcher(content); + if (matcher.find()) { + if (!authConnectionNames.contains(matcher.group(1))) { + return new HashSet<>(Arrays.asList(matcher.group(1))); + } + } + return null; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/authority/JTemplateAuthorityChecker.java b/designer-base/src/main/java/com/fr/design/mainframe/authority/JTemplateAuthorityChecker.java new file mode 100644 index 0000000000..f8b2c8ce6b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/authority/JTemplateAuthorityChecker.java @@ -0,0 +1,184 @@ +package com.fr.design.mainframe.authority; + + +import com.fr.design.dialog.FineJOptionPane; + +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mod.ModClassFilter; +import com.fr.invoke.ClassHelper; + +import com.fr.log.FineLoggerFactory; +import com.fr.rpc.ExceptionHandler; +import com.fr.rpc.RPCInvokerExceptionInfo; +import com.fr.stable.Filter; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.authority.user.UserAuthority; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + + +import static javax.swing.JOptionPane.WARNING_MESSAGE; + + +public class JTemplateAuthorityChecker { + JTemplate jTemplate; + Set authConnectionNames; + Set authDatasetNames; + Map checkerMap = new HashMap<>(); + Set authFailConnectionNames = new HashSet<>(); + Set authFailDatasetNames = new HashSet<>(); + + + public JTemplateAuthorityChecker(JTemplate jTemplate) { + long s = System.currentTimeMillis(); + this.jTemplate = jTemplate; + this.initAuthNames(); + this.initChecker(); + FineLoggerFactory.getLogger().info("JTemplateAuthorityChecker init time consume:" + (System.currentTimeMillis() - s)); + } + + private void initAuthNames() { + UserAuthority templateAuthority = WorkContext.getCurrent().get(UserAuthority.class); + Map> authNamesMap = templateAuthority.getAuthServerDataSetAndConnectionNames(); + if (authNamesMap != null) { + //有权限的数据连接名称 + authConnectionNames = authNamesMap.get(UserAuthority.AUTH_CONNECTION_NAMES); + //有权限的数据集名称(模板数据集和服务器数据集) + authDatasetNames = authNamesMap.get(UserAuthority.AUTH_SERVER_DATASET_NAMES); + Iterator iterator = jTemplate.getTarget().getTableDataNameIterator(); + while (iterator.hasNext()) { + String datasetName = iterator.next(); + authDatasetNames.add(datasetName); + } + } + } + + private void initChecker() { + registerChecker(new NameDatabaseConnectionAuthorityChecker()); + registerChecker(new DSColumnAuthorityChecker()); + registerChecker(new FormulaAuthorityChecker()); + registerChecker(new NameTableDataAuthorityChecker()); + } + + private void registerChecker(ElementAuthorityChecker checker) { + checkerMap.put(checker.getCheckClassName(), checker); + } + + + public boolean isAuthority() { + long s = System.currentTimeMillis(); + //遍历模板对象,根据checkerMap.keySet()把感兴趣的对象找出来 + Map> targetObjects = ClassHelper.searchObject(jTemplate.getTarget(), checkerMap.keySet(), ClassFilter.getInstance()); + + //找到对应的checker,对对象进行检查 + for (String name : targetObjects.keySet()) { + ElementAuthorityChecker checker = checkerMap.get(name); + for (Object object : targetObjects.get(name)) { + if (authConnectionNames != null) { + Set noAuthName = checker.getNoAuthConnectionNames(object, authConnectionNames); + if (noAuthName != null) { + authFailConnectionNames.addAll(noAuthName); + } + } + if (authDatasetNames != null) { + Set noAuthName = checker.getNoAuthDatasetNames(object, authDatasetNames); + if (noAuthName != null) { + authFailDatasetNames.addAll(noAuthName); + } + } + } + } + + FineLoggerFactory.getLogger().info("JTemplateAuthorityChecker check time consume:" + (System.currentTimeMillis() - s)); + return authFailConnectionNames.size() == 0 && authFailDatasetNames.size() == 0; + } + + public void showAuthorityFailPromptDialog() { + StringBuffer stringBuffer = new StringBuffer(); + stringBuffer.append(Toolkit.i18nText("Fine-Design-Basic_Save_Failure")); + stringBuffer.append("\n"); + stringBuffer.append(getPromptInfo(authFailDatasetNames, + Toolkit.i18nText("Fine-Design_Template_Authority_Check_Server_Dataset_Authority"))); + stringBuffer.append(getPromptInfo(authFailConnectionNames, + Toolkit.i18nText("Fine-Design_Template_Authority_Check_Data_Connection_Authority"))); + FineJOptionPane.showMessageDialog( + DesignerContext.getDesignerFrame(), + stringBuffer.toString(), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + } + + private String getPromptInfo(Set authFailNames, String message) { + StringBuffer stringBuffer = new StringBuffer(); + if (authFailNames.size() > 0) { + stringBuffer.append(Toolkit.i18nText("Fine-Design_Template_Authority_Check_Current_Operator_Miss")); + stringBuffer.append(authFailNames.size()); + stringBuffer.append(Toolkit.i18nText("Fine-Design_Report_Ge")); + stringBuffer.append(message); + stringBuffer.append("\n"); + stringBuffer.append(getNoAuthNameSequence(authFailNames)); + } + return stringBuffer.toString(); + } + + private String getNoAuthNameSequence(Set names) { + StringBuffer stringBuffer = new StringBuffer(); + int showMaxCount = 3; + int count = 0; + for (String name : names) { + if (count == showMaxCount) { + stringBuffer.append(Toolkit.i18nText("Fine-Design_Template_Authority_Check_Etc")); + break; + } + stringBuffer.append(name); + if (count != names.size() - 1 && count != showMaxCount - 1) { + stringBuffer.append(";"); + } + count++; + } + stringBuffer.append("\n"); + return stringBuffer.toString(); + } + + static class ClassFilter implements Filter { + + private static final Set FILTER_SET = new HashSet<>(); + private static final Set START_WITH_SET = new HashSet<>(); + private static final Filter INSTANCE = new ModClassFilter(); + + public static Filter getInstance() { + return INSTANCE; + } + + static { + FILTER_SET.add("java.awt.image.BufferedImage"); + FILTER_SET.add("sun.awt.AppContext"); + FILTER_SET.add("com.fr.poly.creator.ECBlockCreator"); + FILTER_SET.add("io.netty.channel.nio.SelectedSelectionKeySet"); + FILTER_SET.add("com.fr.form.ui.ElementCaseImage"); + FILTER_SET.add("this$0"); + START_WITH_SET.add("com.fr.design"); + } + + @Override + public boolean accept(String s) { + if (FILTER_SET.contains(s)) { + return true; + } + for (String start : START_WITH_SET) { + if (s.startsWith(start)) { + return true; + } + } + return false; + } + } +} + diff --git a/designer-base/src/main/java/com/fr/design/mainframe/authority/NameDatabaseConnectionAuthorityChecker.java b/designer-base/src/main/java/com/fr/design/mainframe/authority/NameDatabaseConnectionAuthorityChecker.java new file mode 100644 index 0000000000..96bc0b8c5d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/authority/NameDatabaseConnectionAuthorityChecker.java @@ -0,0 +1,22 @@ +package com.fr.design.mainframe.authority; + +import com.fr.data.impl.NameDatabaseConnection; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +public class NameDatabaseConnectionAuthorityChecker extends ElementAuthorityChecker { + @Override + @Nullable + Set getNoAuthConnectionNames(NameDatabaseConnection nameDatabaseConnection, Set authConnectionNames) { + String name = nameDatabaseConnection.getName(); + if (!authConnectionNames.contains(name)) { + return new HashSet<>(Arrays.asList(name)); + } + return null; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/authority/NameTableDataAuthorityChecker.java b/designer-base/src/main/java/com/fr/design/mainframe/authority/NameTableDataAuthorityChecker.java new file mode 100644 index 0000000000..13e7300856 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/authority/NameTableDataAuthorityChecker.java @@ -0,0 +1,19 @@ +package com.fr.design.mainframe.authority; + +import com.fr.data.impl.NameTableData; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class NameTableDataAuthorityChecker extends ElementAuthorityChecker { + @Override + @Nullable + Set getNoAuthDatasetNames(NameTableData nameTableData, Set authDatasetNames) { + if (!authDatasetNames.contains(nameTableData.getName())) { + return new HashSet<>(Arrays.asList(nameTableData.getName())); + } + return null; + } +}