This commit is contained in:
tanghc
2019-04-01 20:57:56 +08:00
parent 78f85256d6
commit 43c72530d3
109 changed files with 2586 additions and 386 deletions

View File

@@ -23,7 +23,7 @@
<dependency>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-gateway-common</artifactId>
<version>1.0.0-SNAPSHOT</version>
<version>1.1.0-SNAPSHOT</version>
</dependency>
<!-- ↓↓↓ 使用spring cloud zuul ↓↓↓ -->
@@ -50,6 +50,17 @@
-->
<!-- ↑↑↑ 使用spring cloud gateway ↑↑↑ -->
<dependency>
<groupId>net.oschina.durcframework</groupId>
<artifactId>fastmybatis-spring-boot-starter</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
@@ -60,6 +71,12 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencyManagement>

View File

@@ -1,8 +1,14 @@
package com.gitee.sop.gateway.config;
import com.gitee.sop.gateway.entity.IsvInfo;
import com.gitee.sop.gateway.manager.ManagerInitializer;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.bean.ApiContext;
import com.gitee.sop.gatewaycommon.gateway.configuration.AlipayGatewayConfiguration;
import com.gitee.sop.gatewaycommon.manager.IsvRoutePermissionManager;
import com.gitee.sop.gatewaycommon.secret.IsvManager;
import com.gitee.sop.gatewaycommon.zuul.configuration.AlipayZuulConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
@@ -30,6 +36,14 @@ public class GatewayConfig extends AlipayGatewayConfiguration {
appSecretStore.put("2019032617262200001", "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlyb9aUBaljQP/vjmBFe1mF8HsWSvyfC2NTlpT/V9E+sBxTr8TSkbzJCeeeOEm4LCaVXL0Qz63MZoT24v7AIXTuMdj4jyiM/WJ4tjrWAgnmohNOegfntTto16C3l234vXz4ryWZMR/7W+MXy5B92wPGQEJ0LKFwNEoLspDEWZ7RdE53VH7w6y6sIZUfK+YkXWSwehfKPKlx+lDw3zRJ3/yvMF+U+BAdW/MfECe1GuBnCFKnlMRh3UKczWyXWkL6ItOpYHHJi/jx85op5BWDje2pY9QowzfN94+0DB3T7UvZeweu3zlP6diwAJDzLaFQX8ULfWhY+wfKxIRgs9NoiSAQIDAQAB");
ApiContext.getApiConfig().addAppSecret(appSecretStore);
}
@Autowired
ManagerInitializer managerInitializer;
@Override
protected void doAfter() {
managerInitializer.init();
}
}
/**

View File

@@ -1,9 +1,15 @@
package com.gitee.sop.gateway.config;
import com.gitee.sop.gateway.entity.IsvInfo;
import com.gitee.sop.gateway.manager.ManagerInitializer;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.bean.ApiContext;
import com.gitee.sop.gatewaycommon.easyopen.EasyopenZuulConfiguration;
import com.gitee.sop.gatewaycommon.manager.IsvRoutePermissionManager;
import com.gitee.sop.gatewaycommon.secret.IsvManager;
import com.gitee.sop.gatewaycommon.zuul.configuration.AlipayZuulConfiguration;
import com.gitee.sop.gatewaycommon.zuul.configuration.TaobaoZuulConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
@@ -30,6 +36,14 @@ public class ZuulConfig extends AlipayZuulConfiguration {
appSecretStore.put("2019032617262200001", "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlyb9aUBaljQP/vjmBFe1mF8HsWSvyfC2NTlpT/V9E+sBxTr8TSkbzJCeeeOEm4LCaVXL0Qz63MZoT24v7AIXTuMdj4jyiM/WJ4tjrWAgnmohNOegfntTto16C3l234vXz4ryWZMR/7W+MXy5B92wPGQEJ0LKFwNEoLspDEWZ7RdE53VH7w6y6sIZUfK+YkXWSwehfKPKlx+lDw3zRJ3/yvMF+U+BAdW/MfECe1GuBnCFKnlMRh3UKczWyXWkL6ItOpYHHJi/jx85op5BWDje2pY9QowzfN94+0DB3T7UvZeweu3zlP6diwAJDzLaFQX8ULfWhY+wfKxIRgs9NoiSAQIDAQAB");
ApiContext.getApiConfig().addAppSecret(appSecretStore);
}
@Autowired
ManagerInitializer managerInitializer;
@Override
protected void doAfter() {
managerInitializer.init();
}
}
/**

View File

@@ -0,0 +1,48 @@
package com.gitee.sop.gateway.entity;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
/**
* 表名isv_info
* 备注isv信息表
*
* @author tanghc
*/
@Table(name = "isv_info")
@Data
public class IsvInfo {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
/** 数据库字段id */
private Long id;
/** appKey, 数据库字段app_key */
private String appKey;
/** secret, 数据库字段secret */
private String secret;
/** 公钥, 数据库字段pub_key */
private String pubKey;
/** 私钥, 数据库字段pri_key */
private String priKey;
/** 0启用1禁用, 数据库字段status */
private Byte status;
/** 数据库字段gmt_create */
private Date gmtCreate;
/** 数据库字段gmt_modified */
private Date gmtModified;
}

View File

@@ -0,0 +1,39 @@
package com.gitee.sop.gateway.entity;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
/**
* 表名perm_isv_role
* 备注isv角色
*
* @author tanghc
*/
@Table(name = "perm_isv_role")
@Data
public class PermIsvRole {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
/** 数据库字段id */
private Long id;
/** isv_info表id, 数据库字段isv_id */
private Long isvId;
/** 角色code, 数据库字段role_code */
private String roleCode;
/** 数据库字段gmt_create */
private Date gmtCreate;
/** 数据库字段gmt_modified */
private Date gmtModified;
}

View File

@@ -0,0 +1,39 @@
package com.gitee.sop.gateway.entity;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
/**
* 表名perm_role_permission
* 备注:角色权限表
*
* @author tanghc
*/
@Table(name = "perm_role_permission")
@Data
public class PermRolePermission {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
/** 数据库字段id */
private Long id;
/** 角色表code, 数据库字段role_code */
private String roleCode;
/** api_id, 数据库字段route_id */
private String routeId;
/** 数据库字段gmt_create */
private Date gmtCreate;
/** 数据库字段gmt_modified */
private Date gmtModified;
}

View File

@@ -0,0 +1,70 @@
package com.gitee.sop.gateway.manager;
import com.alibaba.fastjson.JSON;
import com.gitee.fastmybatis.core.query.Query;
import com.gitee.sop.gateway.entity.IsvInfo;
import com.gitee.sop.gateway.mapper.IsvInfoMapper;
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
import com.gitee.sop.gatewaycommon.bean.IsvDefinition;
import com.gitee.sop.gatewaycommon.manager.ZookeeperContext;
import com.gitee.sop.gatewaycommon.secret.CacheIsvManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.function.Function;
/**
* @author tanghc
*/
@Component
@Slf4j
public class DbIsvManager extends CacheIsvManager {
@Autowired
IsvInfoMapper isvInfoMapper;
@Autowired
Environment environment;
@Override
public void load(Function<Object, String> secretGetter) {
log.info("从数据库读取ISV信息保存到本地");
List<IsvInfo> isvInfoList = isvInfoMapper.list(new Query());
isvInfoList.stream()
.forEach(isvInfo -> {
IsvDefinition isvDefinition = new IsvDefinition();
BeanUtils.copyProperties(isvInfo, isvDefinition);
String secret = secretGetter.apply(isvInfo);
isvDefinition.setSecret(secret);
this.getIsvCache().put(isvDefinition.getAppKey(), isvDefinition);
});
}
@PostConstruct
protected void after() throws Exception {
ZookeeperContext.setEnvironment(environment);
String isvChannelPath = ZookeeperContext.getIsvInfoChannelPath();
ZookeeperContext.listenPath(isvChannelPath, nodeCache -> {
String nodeData = new String(nodeCache.getCurrentData().getData());
ChannelMsg channelMsg = JSON.parseObject(nodeData, ChannelMsg.class);
final IsvDefinition isvDefinition = JSON.parseObject(channelMsg.getData(), IsvDefinition.class);
switch (channelMsg.getOperation()) {
case "update":
log.info("更新ISV信息isvDefinition:{}", isvDefinition);
update(isvDefinition);
break;
case "remove":
log.info("删除ISVisvDefinition:{}", isvDefinition);
remove(isvDefinition.getAppKey());
break;
}
});
}
}

View File

@@ -0,0 +1,146 @@
package com.gitee.sop.gateway.manager;
import com.alibaba.fastjson.JSON;
import com.gitee.fastmybatis.core.query.Query;
import com.gitee.sop.gateway.entity.IsvInfo;
import com.gitee.sop.gateway.entity.PermIsvRole;
import com.gitee.sop.gateway.entity.PermRolePermission;
import com.gitee.sop.gateway.mapper.IsvInfoMapper;
import com.gitee.sop.gateway.mapper.PermIsvRoleMapper;
import com.gitee.sop.gateway.mapper.PermRolePermissionMapper;
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
import com.gitee.sop.gatewaycommon.bean.IsvRoutePermission;
import com.gitee.sop.gatewaycommon.manager.DefaultIsvRoutePermissionManager;
import com.gitee.sop.gatewaycommon.manager.ZookeeperContext;
import lombok.Data;
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;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
/**
* 从数据库中读取路由权限信息
*
* @author tanghc
*/
@Component
@Slf4j
public class DbIsvRoutePermissionManager extends DefaultIsvRoutePermissionManager {
@Autowired
Environment environment;
@Autowired
PermIsvRoleMapper permIsvRoleMapper;
@Autowired
PermRolePermissionMapper permRolePermissionMapper;
@Autowired
IsvInfoMapper isvInfoMapper;
@Override
public void load() {
// key: appKey, value: roleCodeList
Map<String, List<String>> appKeyRoleCodeMap = this.getIsvRoleCode();
for (Map.Entry<String, List<String>> entry : appKeyRoleCodeMap.entrySet()) {
this.loadIsvRoutePermission(entry.getKey(), entry.getValue());
}
}
public void loadIsvRoutePermission(String appKey, List<String> roleCodeList) {
Collections.sort(roleCodeList);
List<String> routeIdList = this.getRouteIdList(roleCodeList);
String roleCodeListMd5 = DigestUtils.md5Hex(JSON.toJSONString(routeIdList));
IsvRoutePermission isvRoutePermission = new IsvRoutePermission();
isvRoutePermission.setAppKey(appKey);
isvRoutePermission.setRouteIdList(routeIdList);
isvRoutePermission.setRouteIdListMd5(roleCodeListMd5);
this.update(isvRoutePermission);
}
// 获取ISV对应的角色
public Map<String, List<String>> getIsvRoleCode() {
Query query = new Query();
List<PermIsvRole> permIsvRoles = permIsvRoleMapper.list(query);
Map<String, List<String>> appKeyRoleCodeMap = permIsvRoles.stream()
.map(permIsvRole -> {
IsvInfo isvInfo = isvInfoMapper.getById(permIsvRole.getIsvId());
if (isvInfo == null) {
return null;
}
IsvRole isvRole = new IsvRole();
isvRole.appKey = isvInfo.getAppKey();
isvRole.roleCode = permIsvRole.getRoleCode();
return isvRole;
})
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(IsvRole::getAppKey,
mapping(IsvRole::getRoleCode, toList()))
);
return appKeyRoleCodeMap;
}
/**
* 获取角色对应的路由
*
* @param roleCodeList
* @return
*/
public List<String> getRouteIdList(List<String> roleCodeList) {
if (CollectionUtils.isEmpty(roleCodeList)) {
return Collections.emptyList();
}
Query query = new Query();
query.in("role_code", roleCodeList);
List<PermRolePermission> rolePermissionList = permRolePermissionMapper.list(query);
return rolePermissionList.stream()
.map(PermRolePermission::getRouteId)
.collect(Collectors.toList());
}
@Data
static class IsvRole {
private String appKey;
private String roleCode;
}
@PostConstruct
protected void after() throws Exception {
ZookeeperContext.setEnvironment(environment);
String isvChannelPath = ZookeeperContext.getIsvRoutePermissionChannelPath();
ZookeeperContext.listenPath(isvChannelPath, nodeCache -> {
String nodeData = new String(nodeCache.getCurrentData().getData());
ChannelMsg channelMsg = JSON.parseObject(nodeData, ChannelMsg.class);
final IsvRoutePermission isvRoutePermission = JSON.parseObject(channelMsg.getData(), IsvRoutePermission.class);
switch (channelMsg.getOperation()) {
case "reload":
log.info("重新加载路由权限信息isvRoutePermission:{}", isvRoutePermission);
load();
break;
case "update":
log.info("更新ISV路由权限信息isvRoutePermission:{}", isvRoutePermission);
update(isvRoutePermission);
break;
case "remove":
log.info("删除ISV路由权限信息isvRoutePermission:{}", isvRoutePermission);
remove(isvRoutePermission.getAppKey());
break;
}
});
}
}

View File

@@ -0,0 +1,36 @@
package com.gitee.sop.gateway.manager;
import com.gitee.sop.gateway.entity.IsvInfo;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author tanghc
*/
@Component
@Slf4j
public class ManagerInitializer {
@Autowired
private DbIsvManager dbIsvManager;
@Autowired
private DbIsvRoutePermissionManager dbIsvRoutePermissionManager;
public void init() {
ApiConfig apiConfig = ApiConfig.getInstance();
apiConfig.setIsvManager(dbIsvManager);
apiConfig.setIsvRoutePermissionManager(dbIsvRoutePermissionManager);
// 从数据库加载isv信息
log.debug("从数据库加载isv信息");
dbIsvManager.load((isvInfoObj) -> {
IsvInfo isvInfo = (IsvInfo)isvInfoObj;
return isvInfo.getPubKey();
});
log.debug("从数据库加载路由权限信息");
dbIsvRoutePermissionManager.load();
}
}

View File

@@ -0,0 +1,11 @@
package com.gitee.sop.gateway.mapper;
import com.gitee.fastmybatis.core.mapper.CrudMapper;
import com.gitee.sop.gateway.entity.IsvInfo;
/**
* @author tanghc
*/
public interface IsvInfoMapper extends CrudMapper<IsvInfo, Long> {
}

View File

@@ -0,0 +1,11 @@
package com.gitee.sop.gateway.mapper;
import com.gitee.fastmybatis.core.mapper.CrudMapper;
import com.gitee.sop.gateway.entity.PermIsvRole;
/**
* @author tanghc
*/
public interface PermIsvRoleMapper extends CrudMapper<PermIsvRole, Long> {
}

View File

@@ -0,0 +1,11 @@
package com.gitee.sop.gateway.mapper;
import com.gitee.fastmybatis.core.mapper.CrudMapper;
import com.gitee.sop.gateway.entity.PermRolePermission;
/**
* @author tanghc
*/
public interface PermRolePermissionMapper extends CrudMapper<PermRolePermission, Long> {
}

View File

@@ -16,3 +16,9 @@ spring:
lower-case-service-id: true
enabled: true
# 数据源
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/sop?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
username: root
password: root

View File

@@ -11,7 +11,6 @@ import org.apache.curator.retry.ExponentialBackoffRetry;
*/
public class CuratorTest extends TestCase {
private String zookeeperServerAddr = "127.0.0.1:2181";
/**