From 42a868b76964f111614a918f219d57e576e7ffb0 Mon Sep 17 00:00:00 2001 From: tanghc Date: Thu, 4 Jul 2019 17:35:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96admin=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/sop/adminserver/api/isv/IsvApi.java | 25 +++- .../api/isv/param/IsvKeysFormUpdate.java | 5 - .../sop/adminserver/api/service/RouteApi.java | 51 ++++--- .../adminserver/bean/IsvRoutePermission.java | 1 + .../adminserver/bean/SopAdminConstants.java | 2 + .../adminserver/bean/ZookeeperContext.java | 124 +++++++++++++++--- .../sop/adminserver/config/WebConfig.java | 12 ++ .../service/RoutePermissionService.java | 43 +++++- .../src/main/resources/application-dev.yml | 4 + .../src/main/resources/public/index.html | 2 +- ...e7e4b6d5.js => chunk-25908fca.9d8bc0b6.js} | 2 +- ...15951b55.js => chunk-6a68a33e.b6685cb9.js} | 2 +- .../static/js/chunk-73b2dcec.094bb2fa.js | 1 - .../static/js/chunk-73b2dcec.14f248eb.js | 1 + .../gitee/sop/adminserver/CuratorTest.java | 45 +++++++ .../sop-admin-vue/src/views/isv/index.vue | 4 - .../sop-admin-vue/src/views/isv/keys.vue | 6 - .../src/views/service/route/index.vue | 4 +- .../bean/IsvRoutePermission.java | 1 + .../manager/ZookeeperContext.java | 24 +++- .../manager/DbIsvRoutePermissionManager.java | 15 ++- 21 files changed, 294 insertions(+), 80 deletions(-) rename sop-admin/sop-admin-server/src/main/resources/public/static/js/{chunk-25908fca.e7e4b6d5.js => chunk-25908fca.9d8bc0b6.js} (50%) rename sop-admin/sop-admin-server/src/main/resources/public/static/js/{chunk-6a68a33e.15951b55.js => chunk-6a68a33e.b6685cb9.js} (58%) delete mode 100644 sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-73b2dcec.094bb2fa.js create mode 100644 sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-73b2dcec.14f248eb.js create mode 100644 sop-admin/sop-admin-server/src/test/java/com/gitee/sop/adminserver/CuratorTest.java diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/IsvApi.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/IsvApi.java index 27755aa8..273c3553 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/IsvApi.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/IsvApi.java @@ -41,13 +41,16 @@ import com.gitee.sop.adminserver.service.RoutePermissionService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.transaction.annotation.Transactional; import javax.validation.constraints.NotBlank; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; /** @@ -58,7 +61,15 @@ import java.util.stream.Collectors; @Slf4j public class IsvApi { - public static final int SIGN_TYPE_RSA2 = 1; + public static final byte SIGN_TYPE_RSA = 1; + public static final byte SIGN_TYPE_MD5 = 2; + + static Map SIGN_TYPE_MAP = new HashMap<>(); + static { + SIGN_TYPE_MAP.put("rsa", (byte) SIGN_TYPE_RSA); + SIGN_TYPE_MAP.put("md5", (byte) SIGN_TYPE_MD5); + } + @Autowired IsvInfoMapper isvInfoMapper; @@ -74,6 +85,9 @@ public class IsvApi { @Autowired RoutePermissionService routePermissionService; + @Value("${sop.sign-type}") + private String sopSignType; + @Api(name = "isv.info.page") @ApiDocMethod(description = "isv列表", results = { @ApiDocField(name = "pageIndex", description = "第几页", dataType = DataType.INT, example = "1"), @@ -118,6 +132,7 @@ public class IsvApi { CopyUtil.copyProperties(isvKeys, isvDetailVO); } isvDetailVO.setAppKey(appKey); + isvDetailVO.setSignType(getSignType()); return isvDetailVO; } @@ -168,12 +183,17 @@ public class IsvApi { IsvKeysGenVO isvKeysGenVO = this.createIsvKeys(); IsvKeys isvKeys = new IsvKeys(); isvKeys.setAppKey(appKey); + isvKeys.setSignType(getSignType()); CopyUtil.copyPropertiesIgnoreNull(isvKeysGenVO, isvKeys); isvKeysMapper.saveIgnoreNull(isvKeys); this.sendChannelMsg(rec.getAppKey()); } + private byte getSignType() { + return SIGN_TYPE_MAP.getOrDefault(sopSignType, SIGN_TYPE_RSA); + } + @Api(name = "isv.info.update") @ApiDocMethod(description = "修改isv") @Transactional(rollbackFor = Exception.class) @@ -194,6 +214,7 @@ public class IsvApi { if (isvKeys == null) { isvKeys = new IsvKeys(); CopyUtil.copyPropertiesIgnoreNull(param, isvKeys); + isvKeys.setSignType(getSignType()); isvKeysMapper.saveIgnoreNull(isvKeys); } else { CopyUtil.copyPropertiesIgnoreNull(param, isvKeys); @@ -279,7 +300,7 @@ public class IsvApi { routePermissionService.sendIsvRolePermissionToZookeeper(isvInfo.getAppKey(), roleCodeList); } catch (Exception e) { log.error("保存到zookeeper中失败,isvInfo:{}, roleCodeList:{}", isvInfo, roleCodeList); - throw new BizException("保存失败,请查看日志"); + throw new BizException("同步zookeeper失败,请查看网关日志"); } } } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/param/IsvKeysFormUpdate.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/param/IsvKeysFormUpdate.java index d558142f..652db61e 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/param/IsvKeysFormUpdate.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/param/IsvKeysFormUpdate.java @@ -7,7 +7,6 @@ import org.hibernate.validator.constraints.Length; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; /** * @author tanghc @@ -45,8 +44,4 @@ public class IsvKeysFormUpdate { /** 平台生成的私钥, 数据库字段:private_key_platform */ @ApiDocField(description = "平台生成的私钥") private String privateKeyPlatform; - - @ApiDocField(description = "签名类型:1:RSA2,2:MD5") - @NotNull(message = "signType不能为空") - private Byte signType; } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java index 526ebba6..8b582df2 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java @@ -6,7 +6,6 @@ import com.gitee.easyopen.annotation.ApiService; import com.gitee.easyopen.doc.annotation.ApiDoc; import com.gitee.easyopen.doc.annotation.ApiDocMethod; import com.gitee.easyopen.util.CopyUtil; -import com.gitee.fastmybatis.core.query.Query; import com.gitee.sop.adminserver.api.isv.result.RoleVO; import com.gitee.sop.adminserver.api.service.param.RouteAddParam; import com.gitee.sop.adminserver.api.service.param.RouteDeleteParam; @@ -22,7 +21,6 @@ import com.gitee.sop.adminserver.common.ZookeeperPathExistException; import com.gitee.sop.adminserver.common.ZookeeperPathNotExistException; import com.gitee.sop.adminserver.entity.ConfigRouteBase; import com.gitee.sop.adminserver.entity.PermRole; -import com.gitee.sop.adminserver.entity.PermRolePermission; import com.gitee.sop.adminserver.mapper.ConfigRouteBaseMapper; import com.gitee.sop.adminserver.mapper.PermRoleMapper; import com.gitee.sop.adminserver.mapper.PermRolePermissionMapper; @@ -30,14 +28,11 @@ import com.gitee.sop.adminserver.service.RouteConfigService; import com.gitee.sop.adminserver.service.RoutePermissionService; import com.gitee.sop.adminserver.service.RouteService; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -188,6 +183,11 @@ public class RouteApi { return this.getRouteRole(param.getId()); } + /** + * 获取路由对应的角色 + * @param id routeId + * @return + */ private List getRouteRole(String id) { return permRolePermissionMapper.listByColumn("route_id", id) .stream() @@ -203,33 +203,28 @@ public class RouteApi { @Api(name = "route.role.update") @ApiDocMethod(description = "更新路由对应的角色") - @Transactional(rollbackFor = Exception.class) public void updateRouteRole(RoutePermissionParam param) { - String routeId = param.getRouteId(); - // 删除所有数据 - Query delQuery = new Query(); - delQuery.eq("route_id", routeId); - permRolePermissionMapper.deleteByQuery(delQuery); - - List roleCodes = param.getRoleCode(); - if (CollectionUtils.isNotEmpty(roleCodes)) { - List tobeSave = new ArrayList<>(roleCodes.size()); - for (String roleCode : roleCodes) { - PermRolePermission permRolePermission = new PermRolePermission(); - permRolePermission.setRoleCode(roleCode); - permRolePermission.setRouteId(routeId); - tobeSave.add(permRolePermission); - } - // 批量添加 - permRolePermissionMapper.saveBatch(tobeSave); - } - + RoutePermissionParam oldRoutePermission = this.buildOldRoutePermission(param.getRouteId()); + routePermissionService.updateRoutePermission(param); try { - routePermissionService.sendRoutePermissionReloadMsg(); + routePermissionService.sendRoutePermissionReloadMsg(oldRoutePermission); } catch (Exception e) { - log.info("消息推送--路由权限(reload)失败", e); - throw new BizException("修改失败,请查看日志"); + log.error("消息推送--路由权限(reload)失败", e); + // 回滚 + routePermissionService.updateRoutePermission(oldRoutePermission); + throw new BizException(e.getMessage()); } } + private RoutePermissionParam buildOldRoutePermission(String routeId) { + List routeRole = this.getRouteRole(routeId); + List roleCodeList = routeRole.stream() + .map(RoleVO::getRoleCode) + .collect(Collectors.toList()); + RoutePermissionParam routePermissionParam = new RoutePermissionParam(); + routePermissionParam.setRouteId(routeId); + routePermissionParam.setRoleCode(roleCodeList); + return routePermissionParam; + } + } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/IsvRoutePermission.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/IsvRoutePermission.java index ca5ee89a..043b99e6 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/IsvRoutePermission.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/IsvRoutePermission.java @@ -13,4 +13,5 @@ public class IsvRoutePermission { private String appKey; private List routeIdList; private String routeIdListMd5; + private String listenPath; } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/SopAdminConstants.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/SopAdminConstants.java index 958a1977..ba4cf281 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/SopAdminConstants.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/SopAdminConstants.java @@ -14,4 +14,6 @@ public class SopAdminConstants { */ public static final String SOP_MSG_CHANNEL_PATH = "/com.gitee.sop.channel"; + public static final String RELOAD_ROUTE_PERMISSION_PATH = "/com.gitee.sop.route.permission.reload"; + } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java index c97e585e..5d645ae9 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java @@ -4,54 +4,67 @@ import com.gitee.sop.adminserver.common.ZookeeperOperationException; import com.gitee.sop.adminserver.common.ZookeeperPathExistException; import com.gitee.sop.adminserver.common.ZookeeperPathNotExistException; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.cache.ChildData; +import org.apache.curator.framework.recipes.cache.NodeCache; +import org.apache.curator.framework.recipes.cache.NodeCacheListener; import org.apache.curator.framework.recipes.cache.PathChildrenCache; import org.apache.curator.retry.ExponentialBackoffRetry; +import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.data.Stat; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.util.Assert; -import javax.annotation.PostConstruct; +import java.io.Closeable; import java.util.Collections; import java.util.List; +import java.util.function.Consumer; import static com.gitee.sop.adminserver.bean.SopAdminConstants.SOP_MSG_CHANNEL_PATH; /** * @author tanghc */ -@Configuration @Slf4j public class ZookeeperContext { private static CuratorFramework client; - @Value("${spring.cloud.zookeeper.connect-string}") - private String zookeeperServerAddr; + private static Environment environment; - @Value("${spring.cloud.zookeeper.baseSleepTimeMs}") - private String baseSleepTimeMs; + public static void setEnvironment(Environment environment) { + Assert.notNull(environment, "environment不能为null"); + ZookeeperContext.environment = environment; + initZookeeperClient(); + } - @Value("${spring.cloud.zookeeper.maxRetries}") - private String maxRetries; + public synchronized static void initZookeeperClient() { + if (client != null) { + return; + } + setClient(createClient()); + } - @PostConstruct - protected void after() { + public static CuratorFramework createClient() { + String zookeeperServerAddr = environment.getProperty("spring.cloud.zookeeper.connect-string"); if (StringUtils.isBlank(zookeeperServerAddr)) { - throw new IllegalArgumentException("未指定spring.cloud.zookeeper.connect-string参数"); + throw new RuntimeException("未指定spring.cloud.zookeeper.connect-string参数"); } + String baseSleepTimeMs = environment.getProperty("spring.cloud.zookeeper.baseSleepTimeMs"); + String maxRetries = environment.getProperty("spring.cloud.zookeeper.maxRetries"); + log.info("初始化zookeeper客户端,zookeeperServerAddr:{}, baseSleepTimeMs:{}, maxRetries:{}", + zookeeperServerAddr, baseSleepTimeMs, maxRetries); CuratorFramework client = CuratorFrameworkFactory.builder() .connectString(zookeeperServerAddr) .retryPolicy(new ExponentialBackoffRetry(NumberUtils.toInt(baseSleepTimeMs, 3000), NumberUtils.toInt(maxRetries, 3))) .build(); client.start(); - - setClient(client); + return client; } public static String getSopRouteRootPath() { @@ -129,6 +142,7 @@ public class ZookeeperContext { /** * 创建新的path,并赋值。如果path已存在抛异常 + * * @param path 待创建的path * @param data 值 * @throws ZookeeperPathExistException @@ -138,9 +152,26 @@ public class ZookeeperContext { throw new ZookeeperPathExistException("path " + path + " 已存在"); } try { - return getClient().create() + return addPath(path, CreateMode.PERSISTENT, data); + } catch (Exception e) { + throw new ZookeeperOperationException("addPath error path=" + path, e); + } + } + + /** + * 添加节点 + * + * @param path 待创建的path + * @param createMode 节点类型 + * @param data 节点数据 + * @return + */ + public static String addPath(String path, CreateMode createMode, String data) { + try { + return getClient().create() // 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点 .creatingParentContainersIfNeeded() + .withMode(createMode) .forPath(path, data.getBytes()); } catch (Exception e) { throw new ZookeeperOperationException("addPath error path=" + path, e); @@ -149,6 +180,7 @@ public class ZookeeperContext { /** * 删除节点及子节点 + * * @param path */ public static void deletePathDeep(String path) { @@ -157,12 +189,13 @@ public class ZookeeperContext { .deletingChildrenIfNeeded() .forPath(path); } catch (Exception e) { - throw new ZookeeperOperationException("deletePathDeep error path=" + path, e); } } + /** * 创建新的path,并赋值。如果path已存在则不创建 + * * @param path 待创建的path * @param data 值 */ @@ -171,10 +204,7 @@ public class ZookeeperContext { return path; } try { - return getClient().create() - // 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点 - .creatingParentContainersIfNeeded() - .forPath(path, data.getBytes()); + return addPath(path, data); } catch (Exception e) { throw new ZookeeperOperationException("addPathQuietly error path=" + path, e); } @@ -182,6 +212,7 @@ public class ZookeeperContext { /** * 新建或保存节点 + * * @param path * @param data * @return @@ -201,6 +232,7 @@ public class ZookeeperContext { /** * 获取节点内容 + * * @param path * @return * @throws ZookeeperPathNotExistException @@ -247,4 +279,54 @@ public class ZookeeperContext { return childrenCache; } + /** + * 监听一个节点 + * + * @param path + * @param onChange 节点修改后触发 + * @return 返回path + * @throws Exception + */ + public static void listenTempPath(String path, Consumer onChange) throws Exception { + String initData = "{}"; + CuratorFramework client = createClient(); + client.create() + // 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点 + .creatingParentContainersIfNeeded() + .withMode(CreateMode.EPHEMERAL) + .forPath(path, initData.getBytes()); + + final NodeCache cache = new NodeCache(client, path, false); + cache.getListenable().addListener(new NodeCacheListener() { + @Override + public void nodeChanged() throws Exception { + byte[] nodeData = cache.getCurrentData().getData(); + String data = new String(nodeData); + if (!initData.equals(data)) { + onChange.accept(data); + new Thread(new ZKClose(cache, client)).start(); + } + } + }); + cache.start(); + } + + static class ZKClose implements Runnable { + Closeable[] closes; + + public ZKClose(Closeable ...closes) { + this.closes = closes; + } + + @Override + public void run() { + try { + Thread.sleep(2000); + IOUtils.closeQuietly(closes); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/config/WebConfig.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/config/WebConfig.java index 7c8be1f3..07dabc5d 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/config/WebConfig.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/config/WebConfig.java @@ -8,13 +8,17 @@ import com.gitee.easyopen.ApiParamParser; import com.gitee.easyopen.ParamNames; import com.gitee.easyopen.interceptor.ApiInterceptor; import com.gitee.easyopen.session.ApiSessionManager; +import com.gitee.sop.adminserver.bean.ZookeeperContext; import com.gitee.sop.adminserver.interceptor.LoginInterceptor; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; @@ -29,6 +33,9 @@ public class WebConfig { @Value("${admin.access-token.timeout-minutes}") private String accessTokenTimeout; + @Autowired + private Environment environment; + @Bean ApiConfig apiConfig() { ApiConfig apiConfig = new ApiConfig(); @@ -59,4 +66,9 @@ public class WebConfig { return apiConfig; } + @PostConstruct + public void after() { + ZookeeperContext.setEnvironment(environment); + } + } \ No newline at end of file diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RoutePermissionService.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RoutePermissionService.java index 3600a31f..70fbfe31 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RoutePermissionService.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RoutePermissionService.java @@ -2,8 +2,10 @@ package com.gitee.sop.adminserver.service; import com.alibaba.fastjson.JSON; import com.gitee.fastmybatis.core.query.Query; +import com.gitee.sop.adminserver.api.service.param.RoutePermissionParam; import com.gitee.sop.adminserver.bean.ChannelMsg; import com.gitee.sop.adminserver.bean.IsvRoutePermission; +import com.gitee.sop.adminserver.bean.SopAdminConstants; import com.gitee.sop.adminserver.bean.ZookeeperContext; import com.gitee.sop.adminserver.entity.PermIsvRole; import com.gitee.sop.adminserver.entity.PermRolePermission; @@ -16,6 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -93,12 +96,48 @@ public class RoutePermissionService { /** * 推送所有路由权限到zookeeper */ - public void sendRoutePermissionReloadMsg() throws Exception { - ChannelMsg channelMsg = new ChannelMsg("reload", null); + public synchronized void sendRoutePermissionReloadMsg(RoutePermissionParam oldRoutePermission) throws Exception { + String listenPath = SopAdminConstants.RELOAD_ROUTE_PERMISSION_PATH + "/" + System.currentTimeMillis(); + ZookeeperContext.listenTempPath(listenPath, code -> { + // 0成功 + if (!"0".equals(code)) { + log.error("推送所有路由权限到zookeeper失败,进行回滚,msg: {},oldRoutePermission:{}", code, JSON.toJSONString(oldRoutePermission)); + // 回滚 + this.updateRoutePermission(oldRoutePermission); + } + }); + IsvRoutePermission isvRoutePermission = new IsvRoutePermission(); + isvRoutePermission.setListenPath(listenPath); + ChannelMsg channelMsg = new ChannelMsg("reload", isvRoutePermission); String jsonData = JSON.toJSONString(channelMsg); String path = ZookeeperContext.getIsvRoutePermissionChannelPath(); log.info("消息推送--路由权限(reload), path:{}, data:{}", path, jsonData); ZookeeperContext.createOrUpdateData(path, jsonData); } + /** + * 更新路由权限 + * + * @param param + */ + public synchronized void updateRoutePermission(RoutePermissionParam param) { + String routeId = param.getRouteId(); + // 删除所有数据 + Query delQuery = new Query(); + delQuery.eq("route_id", routeId); + permRolePermissionMapper.deleteByQuery(delQuery); + + List roleCodes = param.getRoleCode(); + if (org.apache.commons.collections.CollectionUtils.isNotEmpty(roleCodes)) { + List tobeSave = new ArrayList<>(roleCodes.size()); + for (String roleCode : roleCodes) { + PermRolePermission permRolePermission = new PermRolePermission(); + permRolePermission.setRoleCode(roleCode); + permRolePermission.setRouteId(routeId); + tobeSave.add(permRolePermission); + } + // 批量添加 + permRolePermissionMapper.saveBatch(tobeSave); + } + } } diff --git a/sop-admin/sop-admin-server/src/main/resources/application-dev.yml b/sop-admin/sop-admin-server/src/main/resources/application-dev.yml index 64b56db8..0064c80c 100644 --- a/sop-admin/sop-admin-server/src/main/resources/application-dev.yml +++ b/sop-admin/sop-admin-server/src/main/resources/application-dev.yml @@ -6,6 +6,10 @@ admin: access-token: timeout-minutes: 30 +sop: + # 签名方式,rsa:支付宝开放平台签名方式,md5:淘宝开放平台签名方式 + sign-type: rsa + # 不用改 spring: application: diff --git a/sop-admin/sop-admin-server/src/main/resources/public/index.html b/sop-admin/sop-admin-server/src/main/resources/public/index.html index 60193962..db9c4412 100644 --- a/sop-admin/sop-admin-server/src/main/resources/public/index.html +++ b/sop-admin/sop-admin-server/src/main/resources/public/index.html @@ -1 +1 @@ -SOP Admin
\ No newline at end of file +SOP Admin
\ No newline at end of file diff --git a/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.e7e4b6d5.js b/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.9d8bc0b6.js similarity index 50% rename from sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.e7e4b6d5.js rename to sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.9d8bc0b6.js index 08f5eef6..ec5a6661 100644 --- a/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.e7e4b6d5.js +++ b/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.9d8bc0b6.js @@ -1 +1 @@ -(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-25908fca"],{"021d":function(e,t,a){},"0bac":function(e,t,a){"use strict";var s=a("021d"),i=a.n(s);i.a},cb56:function(e,t,a){"use strict";a.r(t);var s=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("div",{staticClass:"app-container"},[a("el-form",{staticClass:"demo-form-inline",attrs:{inline:!0,model:e.searchFormData,size:"mini"}},[a("el-form-item",{attrs:{label:"appKey"}},[a("el-input",{staticStyle:{width:"250px"},attrs:{clearable:!0,placeholder:"appKey"},model:{value:e.searchFormData.appKey,callback:function(t){e.$set(e.searchFormData,"appKey",t)},expression:"searchFormData.appKey"}})],1),e._v(" "),a("el-form-item",[a("el-button",{attrs:{type:"primary",icon:"el-icon-search"},on:{click:e.onSearchTable}},[e._v("查询")])],1)],1),e._v(" "),a("el-button",{staticStyle:{"margin-bottom":"10px"},attrs:{type:"primary",size:"mini",icon:"el-icon-plus"},on:{click:e.onAdd}},[e._v("新增ISV")]),e._v(" "),a("el-table",{attrs:{data:e.pageInfo.list,border:"",fit:"","highlight-current-row":""}},[a("el-table-column",{attrs:{prop:"id",label:"ID",width:"80"}}),e._v(" "),a("el-table-column",{attrs:{prop:"appKey",label:"appKey",width:"250"}}),e._v(" "),a("el-table-column",{attrs:{prop:"",label:"秘钥",width:"80"},scopedSlots:e._u([{key:"default",fn:function(t){return[a("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(a){return e.onShowKeys(t.row)}}},[e._v("查看")])]}}])}),e._v(" "),a("el-table-column",{attrs:{prop:"roleList",label:"角色"},scopedSlots:e._u([{key:"default",fn:function(t){return[a("div",{domProps:{innerHTML:e._s(e.roleRender(t.row))}})]}}])}),e._v(" "),a("el-table-column",{attrs:{prop:"status",label:"状态",width:"80"},scopedSlots:e._u([{key:"default",fn:function(t){return[1===t.row.status?a("span",{staticStyle:{color:"#67C23A"}},[e._v("已启用")]):e._e(),e._v(" "),2===t.row.status?a("span",{staticStyle:{color:"#F56C6C"}},[e._v("已禁用")]):e._e()]}}])}),e._v(" "),a("el-table-column",{attrs:{prop:"gmtCreate",label:"添加时间",width:"160"}}),e._v(" "),a("el-table-column",{attrs:{prop:"gmtModified",label:"修改时间",width:"160"}}),e._v(" "),a("el-table-column",{attrs:{label:"操作",width:"150"},scopedSlots:e._u([{key:"default",fn:function(t){return[a("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(a){return e.onTableUpdate(t.row)}}},[e._v("修改")]),e._v(" "),a("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(a){return e.onKeysUpdate(t.row)}}},[e._v("秘钥管理")])]}}])})],1),e._v(" "),a("el-pagination",{staticStyle:{"margin-top":"5px"},attrs:{background:"","current-page":e.searchFormData.pageIndex,"page-size":e.searchFormData.pageSize,"page-sizes":[5,10,20,40],total:e.pageInfo.total,layout:"total, sizes, prev, pager, next"},on:{"size-change":e.onSizeChange,"current-change":e.onPageIndexChange}}),e._v(" "),a("el-dialog",{attrs:{title:e.isvDialogTitle,visible:e.isvDialogVisible,"close-on-click-modal":!1},on:{"update:visible":function(t){e.isvDialogVisible=t},close:e.onIsvDialogClose}},[a("el-form",{ref:"isvForm",attrs:{rules:e.rulesIsvForm,model:e.isvDialogFormData,"label-width":"120px",size:"mini"}},[a("el-form-item",{attrs:{label:"appKey"}},[0===e.isvDialogFormData.id?a("span",{staticStyle:{color:"gray"}},[e._v("(系统自动生成)")]):a("span",[e._v(e._s(e.isvDialogFormData.appKey))])]),e._v(" "),a("el-form-item",{attrs:{label:"角色"}},[a("el-checkbox-group",{model:{value:e.isvDialogFormData.roleCode,callback:function(t){e.$set(e.isvDialogFormData,"roleCode",t)},expression:"isvDialogFormData.roleCode"}},e._l(e.roles,function(t){return a("el-checkbox",{key:t.roleCode,attrs:{label:t.roleCode}},[e._v(e._s(t.description))])}),1)],1),e._v(" "),a("el-form-item",{attrs:{label:"状态"}},[a("el-radio-group",{model:{value:e.isvDialogFormData.status,callback:function(t){e.$set(e.isvDialogFormData,"status",t)},expression:"isvDialogFormData.status"}},[a("el-radio",{attrs:{label:1,name:"status"}},[e._v("启用")]),e._v(" "),a("el-radio",{attrs:{label:2,name:"status"}},[e._v("禁用")])],1)],1)],1),e._v(" "),a("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[a("el-button",{on:{click:function(t){e.isvDialogVisible=!1}}},[e._v("取 消")]),e._v(" "),a("el-button",{attrs:{type:"primary"},on:{click:e.onIsvDialogSave}},[e._v("保 存")])],1)],1),e._v(" "),a("el-dialog",{attrs:{title:"秘钥信息",visible:e.isvKeysDialogVisible},on:{"update:visible":function(t){e.isvKeysDialogVisible=t},close:function(t){return e.resetForm("isvKeysFrom")}}},[a("el-form",{ref:"isvKeysFrom",staticClass:"key-view",attrs:{model:e.isvKeysFormData,"label-width":"160px",size:"mini"}},[a("el-form-item",{attrs:{label:""}},[a("el-alert",{attrs:{title:"带 ★ 的分配给开发者",type:"warning",closable:!1}})],1),e._v(" "),a("el-form-item",{attrs:{label:e.selfLabel("appKey")}},[a("span",[e._v(e._s(e.isvKeysFormData.appKey))])]),e._v(" "),a("el-form-item",{attrs:{label:"签名方式"}},[1===e.isvKeysFormData.signType?a("span",[e._v("RSA")]):e._e(),e._v(" "),2===e.isvKeysFormData.signType?a("span",[e._v("MD5")]):e._e()]),e._v(" "),a("el-form-item",{directives:[{name:"show",rawName:"v-show",value:e.showKeys(),expression:"showKeys()"}],attrs:{label:"秘钥格式"}},[1===e.isvKeysFormData.keyFormat?a("span",[e._v("PKCS8(JAVA适用)")]):e._e(),e._v(" "),2===e.isvKeysFormData.keyFormat?a("span",[e._v("PKCS1(非JAVA适用)")]):e._e()]),e._v(" "),a("el-form-item",{directives:[{name:"show",rawName:"v-show",value:2===e.isvKeysFormData.signType,expression:"isvKeysFormData.signType === 2"}],attrs:{label:e.selfLabel("secret")}},[a("span",[e._v(e._s(e.isvKeysFormData.secret))])]),e._v(" "),a("fieldset",{directives:[{name:"show",rawName:"v-show",value:e.showKeys(),expression:"showKeys()"}]},[a("legend",[e._v("ISV公私钥")]),e._v(" "),a("el-form-item",{attrs:{label:"ISV公钥"}},[a("el-input",{attrs:{type:"textarea",readonly:""},model:{value:e.isvKeysFormData.publicKeyIsv,callback:function(t){e.$set(e.isvKeysFormData,"publicKeyIsv",t)},expression:"isvKeysFormData.publicKeyIsv"}})],1),e._v(" "),a("el-form-item",{attrs:{label:e.selfLabel("ISV私钥")}},[a("el-input",{attrs:{type:"textarea",readonly:""},model:{value:e.isvKeysFormData.privateKeyIsv,callback:function(t){e.$set(e.isvKeysFormData,"privateKeyIsv",t)},expression:"isvKeysFormData.privateKeyIsv"}})],1)],1),e._v(" "),a("fieldset",{directives:[{name:"show",rawName:"v-show",value:e.showKeys(),expression:"showKeys()"}]},[a("legend",[e._v("平台公私钥")]),e._v(" "),a("el-form-item",{attrs:{label:e.selfLabel("平台公钥")}},[a("el-input",{attrs:{type:"textarea",readonly:""},model:{value:e.isvKeysFormData.publicKeyPlatform,callback:function(t){e.$set(e.isvKeysFormData,"publicKeyPlatform",t)},expression:"isvKeysFormData.publicKeyPlatform"}})],1),e._v(" "),a("el-form-item",{attrs:{prop:"privateKeyPlatform",label:"平台私钥"}},[a("el-input",{attrs:{type:"textarea",readonly:""},model:{value:e.isvKeysFormData.privateKeyPlatform,callback:function(t){e.$set(e.isvKeysFormData,"privateKeyPlatform",t)},expression:"isvKeysFormData.privateKeyPlatform"}})],1)],1)],1),e._v(" "),a("span",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[a("el-button",{on:{click:function(t){e.isvKeysDialogVisible=!1}}},[e._v("关 闭")])],1)],1)],1)},i=[],o={data:function(){return{searchFormData:{appKey:"",pageIndex:1,pageSize:10},pageInfo:{list:[],total:0},roles:[],isvDialogVisible:!1,isvDialogTitle:"新增ISV",isvDialogFormData:{id:0,status:1,roleCode:[]},rulesIsvForm:{appKey:[{required:!0,message:"不能为空",trigger:"blur"},{min:1,max:100,message:"长度在 1 到 100 个字符",trigger:"blur"}]},isvKeysDialogVisible:!1,isvKeysFormData:{appKey:"",secret:"",publicKeyIsv:"",privateKeyIsv:"",publicKeyPlatform:"",privateKeyPlatform:"",signType:""}}},created:function(){this.loadTable(),this.loadRouteRole()},methods:{loadTable:function(){this.post("isv.info.page",this.searchFormData,function(e){this.pageInfo=e.data})},loadRouteRole:function(){0===this.roles.length&&this.post("role.listall",{},function(e){this.roles=e.data})},onShowKeys:function(e){this.post("isv.keys.get",{appKey:e.appKey},function(e){var t=this;this.isvKeysDialogVisible=!0,this.$nextTick(function(){Object.assign(t.isvKeysFormData,e.data)})})},onSearchTable:function(){this.loadTable()},onTableUpdate:function(e){var t=this;this.isvDialogTitle="修改ISV",this.isvDialogVisible=!0,this.$nextTick(function(){t.post("isv.info.get",{id:e.id},function(e){for(var t=e.data,a=t.roleList,s=[],i=0;i0?t.join(", "):'未授权'},onRouteDialogSave:function(){var e=this;this.$refs.routeDialogFormRef.validate(function(t){if(t){var o=e.routeDialogFormData.id?"route.update":"route.add";e.routeDialogFormData.serviceId=e.serviceId,e.post(o,e.routeDialogFormData,function(){this.routeDialogVisible=!1,this.loadTable()})}})},onAuthDialogSave:function(){this.post("route.role.update",this.authDialogFormData,function(){this.authDialogVisible=!1,this.loadTable()})},addService:function(){this.addServiceDialogVisible=!0},closeAddServiceDlg:function(){this.$refs.addServiceForm.resetFields()},onAddService:function(){var e=this;this.$refs.addServiceForm.validate(function(t){t&&e.post("service.custom.add",e.addServiceForm,function(e){this.addServiceDialogVisible=!1,this.tip("添加成功"),this.loadTree()})})},onDelService:function(e){var t=e.serviceId;this.confirm("确认要删除服务"+t+"吗,【对应的路由配置会一起删除】",function(e){var o={serviceId:t};this.post("service.custom.del",o,function(){e(),this.tip("删除成功"),this.loadTree()})})}}},l=r,s=(o("55a2"),o("2877")),n=Object(s["a"])(l,a,i,!1,null,null,null);t["default"]=n.exports},"55a2":function(e,t,o){"use strict";var a=o("b294"),i=o.n(a);i.a},b294:function(e,t,o){}}]); \ No newline at end of file +(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-6a68a33e"],{1248:function(e,t,o){"use strict";o.r(t);var a=function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("div",{staticClass:"app-container"},[o("el-container",[o("el-aside",{staticStyle:{"min-height":"300px",width:"250px"}},[o("el-button",{attrs:{type:"primary",plain:"",size:"mini",icon:"el-icon-plus"},on:{click:function(t){return t.stopPropagation(),e.addService(t)}}},[e._v("\n 新建服务\n ")]),e._v(" "),o("el-input",{staticStyle:{"margin-bottom":"10px","margin-top":"10px"},attrs:{"prefix-icon":"el-icon-search",placeholder:"搜索服务...",size:"mini",clearable:""},model:{value:e.filterText,callback:function(t){e.filterText=t},expression:"filterText"}}),e._v(" "),o("el-tree",{ref:"serviceTree",staticClass:"filter-tree",attrs:{data:e.treeData,props:e.defaultProps,"filter-node-method":e.filterNode,"highlight-current":!0,"expand-on-click-node":!1,"empty-text":"无数据","node-key":"serviceId","default-expand-all":""},on:{"node-click":e.onNodeClick},scopedSlots:e._u([{key:"default",fn:function(t){t.node;var a=t.data;return o("span",{staticClass:"custom-tree-node"},[o("div",[o("el-tooltip",{directives:[{name:"show",rawName:"v-show",value:a.custom,expression:"data.custom"}],staticClass:"item",attrs:{content:"自定义服务",effect:"light",placement:"left"}},[o("i",{staticClass:"el-icon-warning-outline"})]),e._v(" "),a.label.length0?t.join(", "):'未授权'},onRouteDialogSave:function(){var e=this;this.$refs.routeDialogFormRef.validate(function(t){if(t){var o=e.routeDialogFormData.id?"route.update":"route.add";e.routeDialogFormData.serviceId=e.serviceId,e.post(o,e.routeDialogFormData,function(){this.routeDialogVisible=!1,this.loadTable()})}})},onAuthDialogSave:function(){this.post("route.role.update",this.authDialogFormData,function(){this.authDialogVisible=!1,this.loadTable()})},addService:function(){this.addServiceDialogVisible=!0},closeAddServiceDlg:function(){this.$refs.addServiceForm.resetFields()},onAddService:function(){var e=this;this.$refs.addServiceForm.validate(function(t){t&&e.post("service.custom.add",e.addServiceForm,function(e){this.addServiceDialogVisible=!1,this.tip("添加成功"),this.loadTree()})})},onDelService:function(e){var t=e.serviceId;this.confirm("确认要删除服务"+t+"吗,【对应的路由配置会一起删除】",function(e){var o={serviceId:t};this.post("service.custom.del",o,function(){e(),this.tip("删除成功"),this.loadTree()})})}}},l=r,s=(o("55a2"),o("2877")),n=Object(s["a"])(l,a,i,!1,null,null,null);t["default"]=n.exports},"55a2":function(e,t,o){"use strict";var a=o("b294"),i=o.n(a);i.a},b294:function(e,t,o){}}]); \ No newline at end of file diff --git a/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-73b2dcec.094bb2fa.js b/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-73b2dcec.094bb2fa.js deleted file mode 100644 index fa16b15b..00000000 --- a/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-73b2dcec.094bb2fa.js +++ /dev/null @@ -1 +0,0 @@ -(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-73b2dcec"],{"29fd":function(e,t,s){},"3bf7":function(e,t,s){"use strict";s.r(t);var a=function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("div",{staticClass:"app-container"},[s("el-button",{staticClass:"el-icon-back",attrs:{type:"text"},on:{click:e.onBack}},[e._v("返回")]),e._v(" "),s("el-form",{ref:"isvKeysForm",staticStyle:{width:"700px"},attrs:{rules:e.rulesIsvKeysForm,model:e.isvKeysFormData,"label-width":"160px",size:"mini"}},[s("el-form-item",{attrs:{label:""}},[s("el-alert",{attrs:{title:"带 ★ 的分配给开发者",type:"warning",closable:!1}})],1),e._v(" "),s("el-form-item",{attrs:{label:e.selfLabel("appKey")}},[s("div",[e._v(e._s(e.isvKeysFormData.appKey))])]),e._v(" "),s("el-form-item",{attrs:{label:"签名方式"}},[s("el-radio-group",{model:{value:e.isvKeysFormData.signType,callback:function(t){e.$set(e.isvKeysFormData,"signType",t)},expression:"isvKeysFormData.signType"}},[s("el-radio",{attrs:{label:1,name:"status"}},[e._v("RSA")]),e._v(" "),s("el-radio",{attrs:{label:2,name:"status"}},[e._v("MD5")])],1)],1),e._v(" "),s("el-form-item",{directives:[{name:"show",rawName:"v-show",value:e.showKeys(),expression:"showKeys()"}],attrs:{label:"秘钥格式"}},[s("el-radio-group",{model:{value:e.isvKeysFormData.keyFormat,callback:function(t){e.$set(e.isvKeysFormData,"keyFormat",t)},expression:"isvKeysFormData.keyFormat"}},[s("el-radio",{attrs:{label:1,name:"keyFormat"}},[e._v("PKCS8(JAVA适用)")]),e._v(" "),s("el-radio",{attrs:{label:2,name:"keyFormat"}},[e._v("PKCS1(非JAVA适用)")])],1)],1),e._v(" "),s("el-form-item",{directives:[{name:"show",rawName:"v-show",value:2===e.isvKeysFormData.signType,expression:"isvKeysFormData.signType === 2"}],attrs:{prop:"secret",label:e.selfLabel("secret")}},[s("el-input",{model:{value:e.isvKeysFormData.secret,callback:function(t){e.$set(e.isvKeysFormData,"secret",t)},expression:"isvKeysFormData.secret"}}),e._v(" "),s("el-button",{attrs:{type:"text"},on:{click:e.onGenSecret}},[e._v("重新生成")])],1),e._v(" "),s("fieldset",{directives:[{name:"show",rawName:"v-show",value:e.showKeys(),expression:"showKeys()"}]},[s("legend",[e._v("ISV公私钥")]),e._v(" "),s("el-form-item",{staticClass:"gen-key"},[s("el-button",{attrs:{type:"text"},on:{click:e.onGenKeysIsv}},[e._v("重新生成")])],1),e._v(" "),s("el-form-item",{attrs:{prop:"publicKeyIsv",label:"ISV公钥"}},[s("el-input",{attrs:{type:"textarea"},model:{value:e.isvKeysFormData.publicKeyIsv,callback:function(t){e.$set(e.isvKeysFormData,"publicKeyIsv",t)},expression:"isvKeysFormData.publicKeyIsv"}})],1),e._v(" "),s("el-form-item",{attrs:{prop:"privateKeyIsv",label:e.selfLabel("ISV私钥")}},[s("el-input",{attrs:{type:"textarea"},model:{value:e.isvKeysFormData.privateKeyIsv,callback:function(t){e.$set(e.isvKeysFormData,"privateKeyIsv",t)},expression:"isvKeysFormData.privateKeyIsv"}})],1)],1),e._v(" "),s("fieldset",{directives:[{name:"show",rawName:"v-show",value:e.showKeys(),expression:"showKeys()"}]},[s("legend",[e._v("平台公私钥")]),e._v(" "),s("el-form-item",{staticClass:"gen-key"},[s("el-button",{attrs:{type:"text"},on:{click:e.onGenKeysPlatform}},[e._v("重新生成")])],1),e._v(" "),s("el-form-item",{attrs:{prop:"publicKeyPlatform",label:e.selfLabel("平台公钥")}},[s("el-input",{attrs:{type:"textarea"},model:{value:e.isvKeysFormData.publicKeyPlatform,callback:function(t){e.$set(e.isvKeysFormData,"publicKeyPlatform",t)},expression:"isvKeysFormData.publicKeyPlatform"}})],1),e._v(" "),s("el-form-item",{attrs:{prop:"privateKeyPlatform",label:"平台私钥"}},[s("el-input",{attrs:{type:"textarea"},model:{value:e.isvKeysFormData.privateKeyPlatform,callback:function(t){e.$set(e.isvKeysFormData,"privateKeyPlatform",t)},expression:"isvKeysFormData.privateKeyPlatform"}})],1)],1),e._v(" "),s("el-form-item",[s("el-button",{attrs:{type:"primary"},on:{click:e.onSubmit}},[e._v("保存")]),e._v(" "),s("el-button",{on:{click:e.onBack}},[e._v("取消")])],1)],1)],1)},i=[],r={data:function(){var e=this,t=function(t,s,a){2===e.isvKeysFormData.signType&&(""===s&&a(new Error("不能为空")),s.length>200&&a(new Error("长度不能超过200"))),a()},s=function(t,s,a){1===e.isvKeysFormData.signType&&""===s&&a(new Error("不能为空")),a()};return{isvKeysFormData:{appKey:"",secret:"",keyFormat:1,publicKeyIsv:"",privateKeyIsv:"",publicKeyPlatform:"",privateKeyPlatform:"",signType:1},rulesIsvKeysForm:{secret:[{validator:t,trigger:"blur"}],publicKeyIsv:[{validator:s,trigger:"blur"}],privateKeyIsv:[{validator:s,trigger:"blur"}]}}},created:function(){var e=this.$route.query;this.isvKeysFormData.appKey=e.appKey,this.loadForm()},methods:{loadForm:function(){this.post("isv.keys.get",{appKey:this.isvKeysFormData.appKey},function(e){Object.assign(this.isvKeysFormData,e.data)})},selfLabel:function(e){return"★ "+e},onSubmit:function(){var e=this;this.$refs.isvKeysForm.validate(function(t){t&&e.post("isv.keys.update",e.isvKeysFormData,function(){this.tip("保存成功")})})},onBack:function(){this.$router.push({path:"list"})},onGenKeysPlatform:function(){this.post("isv.keys.gen",{},function(e){this.tip("生成公私钥成功");var t=e.data;this.isvKeysFormData.publicKeyPlatform=t.publicKey,this.isvKeysFormData.privateKeyPlatform=t.privateKey})},onGenKeysIsv:function(){this.post("isv.keys.gen",{keyFormat:this.isvKeysFormData.keyFormat},function(e){this.tip("生成公私钥成功");var t=e.data;this.isvKeysFormData.publicKeyIsv=t.publicKey,this.isvKeysFormData.privateKeyIsv=t.privateKey})},onGenSecret:function(){this.post("isv.secret.gen",{},function(e){this.isvKeysFormData.secret=e.data})},showKeys:function(){return 1===this.isvKeysFormData.signType}}},o=r,l=(s("8b91"),s("2877")),n=Object(l["a"])(o,a,i,!1,null,null,null);t["default"]=n.exports},"8b91":function(e,t,s){"use strict";var a=s("29fd"),i=s.n(a);i.a}}]); \ No newline at end of file diff --git a/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-73b2dcec.14f248eb.js b/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-73b2dcec.14f248eb.js new file mode 100644 index 00000000..d4f46ee6 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-73b2dcec.14f248eb.js @@ -0,0 +1 @@ +(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-73b2dcec"],{"29fd":function(e,t,s){},"3bf7":function(e,t,s){"use strict";s.r(t);var a=function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("div",{staticClass:"app-container"},[s("el-button",{staticClass:"el-icon-back",attrs:{type:"text"},on:{click:e.onBack}},[e._v("返回")]),e._v(" "),s("el-form",{ref:"isvKeysForm",staticStyle:{width:"700px"},attrs:{rules:e.rulesIsvKeysForm,model:e.isvKeysFormData,"label-width":"160px",size:"mini"}},[s("el-form-item",{attrs:{label:""}},[s("el-alert",{attrs:{title:"带 ★ 的分配给开发者",type:"warning",closable:!1}})],1),e._v(" "),s("el-form-item",{attrs:{label:e.selfLabel("appKey")}},[s("div",[e._v(e._s(e.isvKeysFormData.appKey))])]),e._v(" "),s("el-form-item",{directives:[{name:"show",rawName:"v-show",value:e.showKeys(),expression:"showKeys()"}],attrs:{label:"秘钥格式"}},[s("el-radio-group",{model:{value:e.isvKeysFormData.keyFormat,callback:function(t){e.$set(e.isvKeysFormData,"keyFormat",t)},expression:"isvKeysFormData.keyFormat"}},[s("el-radio",{attrs:{label:1,name:"keyFormat"}},[e._v("PKCS8(JAVA适用)")]),e._v(" "),s("el-radio",{attrs:{label:2,name:"keyFormat"}},[e._v("PKCS1(非JAVA适用)")])],1)],1),e._v(" "),s("el-form-item",{directives:[{name:"show",rawName:"v-show",value:2===e.isvKeysFormData.signType,expression:"isvKeysFormData.signType === 2"}],attrs:{prop:"secret",label:e.selfLabel("secret")}},[s("el-input",{model:{value:e.isvKeysFormData.secret,callback:function(t){e.$set(e.isvKeysFormData,"secret",t)},expression:"isvKeysFormData.secret"}}),e._v(" "),s("el-button",{attrs:{type:"text"},on:{click:e.onGenSecret}},[e._v("重新生成")])],1),e._v(" "),s("fieldset",{directives:[{name:"show",rawName:"v-show",value:e.showKeys(),expression:"showKeys()"}]},[s("legend",[e._v("ISV公私钥")]),e._v(" "),s("el-form-item",{staticClass:"gen-key"},[s("el-button",{attrs:{type:"text"},on:{click:e.onGenKeysIsv}},[e._v("重新生成")])],1),e._v(" "),s("el-form-item",{attrs:{prop:"publicKeyIsv",label:"ISV公钥"}},[s("el-input",{attrs:{type:"textarea"},model:{value:e.isvKeysFormData.publicKeyIsv,callback:function(t){e.$set(e.isvKeysFormData,"publicKeyIsv",t)},expression:"isvKeysFormData.publicKeyIsv"}})],1),e._v(" "),s("el-form-item",{attrs:{prop:"privateKeyIsv",label:e.selfLabel("ISV私钥")}},[s("el-input",{attrs:{type:"textarea"},model:{value:e.isvKeysFormData.privateKeyIsv,callback:function(t){e.$set(e.isvKeysFormData,"privateKeyIsv",t)},expression:"isvKeysFormData.privateKeyIsv"}})],1)],1),e._v(" "),s("fieldset",{directives:[{name:"show",rawName:"v-show",value:e.showKeys(),expression:"showKeys()"}]},[s("legend",[e._v("平台公私钥")]),e._v(" "),s("el-form-item",{staticClass:"gen-key"},[s("el-button",{attrs:{type:"text"},on:{click:e.onGenKeysPlatform}},[e._v("重新生成")])],1),e._v(" "),s("el-form-item",{attrs:{prop:"publicKeyPlatform",label:e.selfLabel("平台公钥")}},[s("el-input",{attrs:{type:"textarea"},model:{value:e.isvKeysFormData.publicKeyPlatform,callback:function(t){e.$set(e.isvKeysFormData,"publicKeyPlatform",t)},expression:"isvKeysFormData.publicKeyPlatform"}})],1),e._v(" "),s("el-form-item",{attrs:{prop:"privateKeyPlatform",label:"平台私钥"}},[s("el-input",{attrs:{type:"textarea"},model:{value:e.isvKeysFormData.privateKeyPlatform,callback:function(t){e.$set(e.isvKeysFormData,"privateKeyPlatform",t)},expression:"isvKeysFormData.privateKeyPlatform"}})],1)],1),e._v(" "),s("el-form-item",[s("el-button",{attrs:{type:"primary"},on:{click:e.onSubmit}},[e._v("保存")]),e._v(" "),s("el-button",{on:{click:e.onBack}},[e._v("取消")])],1)],1)],1)},i=[],r={data:function(){var e=this,t=function(t,s,a){2===e.isvKeysFormData.signType&&(""===s&&a(new Error("不能为空")),s.length>200&&a(new Error("长度不能超过200"))),a()},s=function(t,s,a){1===e.isvKeysFormData.signType&&""===s&&a(new Error("不能为空")),a()};return{isvKeysFormData:{appKey:"",secret:"",keyFormat:1,publicKeyIsv:"",privateKeyIsv:"",publicKeyPlatform:"",privateKeyPlatform:"",signType:1},rulesIsvKeysForm:{secret:[{validator:t,trigger:"blur"}],publicKeyIsv:[{validator:s,trigger:"blur"}],privateKeyIsv:[{validator:s,trigger:"blur"}]}}},created:function(){var e=this.$route.query;this.isvKeysFormData.appKey=e.appKey,this.loadForm()},methods:{loadForm:function(){this.post("isv.keys.get",{appKey:this.isvKeysFormData.appKey},function(e){Object.assign(this.isvKeysFormData,e.data)})},selfLabel:function(e){return"★ "+e},onSubmit:function(){var e=this;this.$refs.isvKeysForm.validate(function(t){t&&e.post("isv.keys.update",e.isvKeysFormData,function(){this.tip("保存成功")})})},onBack:function(){this.$router.push({path:"list"})},onGenKeysPlatform:function(){this.post("isv.keys.gen",{},function(e){this.tip("生成公私钥成功");var t=e.data;this.isvKeysFormData.publicKeyPlatform=t.publicKey,this.isvKeysFormData.privateKeyPlatform=t.privateKey})},onGenKeysIsv:function(){this.post("isv.keys.gen",{keyFormat:this.isvKeysFormData.keyFormat},function(e){this.tip("生成公私钥成功");var t=e.data;this.isvKeysFormData.publicKeyIsv=t.publicKey,this.isvKeysFormData.privateKeyIsv=t.privateKey})},onGenSecret:function(){this.post("isv.secret.gen",{},function(e){this.isvKeysFormData.secret=e.data})},showKeys:function(){return 1===this.isvKeysFormData.signType}}},o=r,l=(s("8b91"),s("2877")),n=Object(l["a"])(o,a,i,!1,null,null,null);t["default"]=n.exports},"8b91":function(e,t,s){"use strict";var a=s("29fd"),i=s.n(a);i.a}}]); \ No newline at end of file diff --git a/sop-admin/sop-admin-server/src/test/java/com/gitee/sop/adminserver/CuratorTest.java b/sop-admin/sop-admin-server/src/test/java/com/gitee/sop/adminserver/CuratorTest.java new file mode 100644 index 00000000..7cf5c1ed --- /dev/null +++ b/sop-admin/sop-admin-server/src/test/java/com/gitee/sop/adminserver/CuratorTest.java @@ -0,0 +1,45 @@ +package com.gitee.sop.adminserver; + +import com.gitee.sop.adminserver.bean.SopAdminConstants; +import junit.framework.TestCase; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.apache.zookeeper.data.Stat; + +public class CuratorTest extends TestCase { + + private static String zookeeperServerAddr = "localhost:2181"; + + static CuratorFramework client; + + public CuratorTest() { + client = CuratorFrameworkFactory.builder() + .connectString(zookeeperServerAddr) + .retryPolicy(new ExponentialBackoffRetry(1000, 3)) + .build(); + + client.start(); + } + + /** + * 递归删除节点,只能在测试环境用。 + * + * @throws Exception + */ + public void testDel() { + try { + client.delete() + .deletingChildrenIfNeeded() + .forPath(SopAdminConstants.RELOAD_ROUTE_PERMISSION_PATH); + } catch (Exception e) { + } + } + + public void testCheck() throws Exception { + String path = SopAdminConstants.RELOAD_ROUTE_PERMISSION_PATH + "/1562231019332"; + Stat stat = client.checkExists().forPath(path); + System.out.println(path + (stat == null ? "不存在" : "存在")); + } + +} \ No newline at end of file diff --git a/sop-admin/sop-admin-vue/src/views/isv/index.vue b/sop-admin/sop-admin-vue/src/views/isv/index.vue index 4c08fb7f..6b732348 100644 --- a/sop-admin/sop-admin-vue/src/views/isv/index.vue +++ b/sop-admin/sop-admin-vue/src/views/isv/index.vue @@ -141,10 +141,6 @@ {{ isvKeysFormData.appKey }} - - RSA - MD5 - PKCS8(JAVA适用) PKCS1(非JAVA适用) diff --git a/sop-admin/sop-admin-vue/src/views/isv/keys.vue b/sop-admin/sop-admin-vue/src/views/isv/keys.vue index 812f5857..5ea318bb 100644 --- a/sop-admin/sop-admin-vue/src/views/isv/keys.vue +++ b/sop-admin/sop-admin-vue/src/views/isv/keys.vue @@ -19,12 +19,6 @@
{{ isvKeysFormData.appKey }}
- - - RSA - MD5 - - PKCS8(JAVA适用) diff --git a/sop-admin/sop-admin-vue/src/views/service/route/index.vue b/sop-admin/sop-admin-vue/src/views/service/route/index.vue index 8ef40687..5845c8bc 100644 --- a/sop-admin/sop-admin-vue/src/views/service/route/index.vue +++ b/sop-admin/sop-admin-vue/src/views/service/route/index.vue @@ -214,8 +214,8 @@ label-width="120px" size="mini" > - - + + {{ authDialogFormData.routeId }} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/IsvRoutePermission.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/IsvRoutePermission.java index b3894f29..2836cf67 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/IsvRoutePermission.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/IsvRoutePermission.java @@ -14,5 +14,6 @@ public class IsvRoutePermission { private String appKey; private List routeIdList = Collections.emptyList(); private String routeIdListMd5; + private String listenPath; } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ZookeeperContext.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ZookeeperContext.java index 7507e653..79c688d8 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ZookeeperContext.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ZookeeperContext.java @@ -28,15 +28,22 @@ public class ZookeeperContext { private static CuratorFramework client; + private static Environment environment; + public static void setEnvironment(Environment environment) { Assert.notNull(environment, "environment不能为null"); - initZookeeperClient(environment); + ZookeeperContext.environment = environment; + initZookeeperClient(); } - public synchronized static void initZookeeperClient(Environment environment) { + public synchronized static void initZookeeperClient() { if (client != null) { return; } + setClient(createClient()); + } + + public static CuratorFramework createClient() { String zookeeperServerAddr = environment.getProperty("spring.cloud.zookeeper.connect-string"); if (StringUtils.isBlank(zookeeperServerAddr)) { throw new RuntimeException("未指定spring.cloud.zookeeper.connect-string参数"); @@ -51,8 +58,7 @@ public class ZookeeperContext { .build(); client.start(); - - setClient(client); + return client; } public static String getRouteRootPath() { @@ -100,6 +106,16 @@ public class ZookeeperContext { .forPath(path, data.getBytes()); } + /** + * 更新节点 + * @param path + * @param data + * @throws Exception + */ + public static void updatePath(String path, String data) throws Exception { + getClient().setData().forPath(path, data.getBytes()); + } + /** * 创建path,如果path存在不报错,静默返回path名称 * diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvRoutePermissionManager.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvRoutePermissionManager.java index 4a6ee0bb..8285500b 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvRoutePermissionManager.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvRoutePermissionManager.java @@ -17,7 +17,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.digest.DigestUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; -import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import javax.annotation.PostConstruct; @@ -129,7 +128,19 @@ public class DbIsvRoutePermissionManager extends DefaultIsvRoutePermissionManage switch (channelMsg.getOperation()) { case "reload": log.info("重新加载路由权限信息,isvRoutePermission:{}", isvRoutePermission); - load(); + String listenPath = isvRoutePermission.getListenPath(); + String code = "0"; + try { + load(); + } catch (Exception e) { + log.error("重新加载路由权限失败, channelMsg:{}", channelMsg, e); + code = e.getMessage(); + } + try { + ZookeeperContext.updatePath(listenPath, code); + } catch (Exception e1) { + log.error("重新加载路由权限信息, zookeeper操作失败, path: {}", listenPath, e1); + } break; case "update": log.info("更新ISV路由权限信息,isvRoutePermission:{}", isvRoutePermission);