From 34cab564373856807d5fba8d44dd4880fd8bcf81 Mon Sep 17 00:00:00 2001 From: fengfei Date: Tue, 12 Sep 2017 20:25:15 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3Windows=E4=B8=AD=E6=96=87?= =?UTF-8?q?=E4=B9=B1=E7=A0=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 112 +-- .../lanproxy/server/config/ProxyConfig.java | 799 +++++++++--------- .../server/config/web/routes/RouteConfig.java | 331 ++++---- .../src/test/resources/config.properties | 28 +- 4 files changed, 640 insertions(+), 630 deletions(-) diff --git a/pom.xml b/pom.xml index 6173837..96fd0c1 100644 --- a/pom.xml +++ b/pom.xml @@ -1,53 +1,59 @@ - - - 4.0.0 - org.fengfei - lanproxy - pom - 0.1 - lanproxy - http://maven.apache.org - - - io.netty - netty-all - 4.0.36.Final - - - org.slf4j - slf4j-api - 1.7.5 - - - org.slf4j - slf4j-log4j12 - 1.7.5 - - - junit - junit - 4.12 - test - - - - proxy-common - proxy-protocol - proxy-server - proxy-client - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - 1.8 - 1.8 - - - - - + + + 4.0.0 + org.fengfei + lanproxy + pom + 0.1 + lanproxy + http://maven.apache.org + + UTF-8 + UTF-8 + UTF-8 + + + + io.netty + netty-all + 4.0.36.Final + + + org.slf4j + slf4j-api + 1.7.5 + + + org.slf4j + slf4j-log4j12 + 1.7.5 + + + junit + junit + 4.12 + test + + + + proxy-common + proxy-protocol + proxy-server + proxy-client + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.8 + 1.8 + UTF-8 + + + + + diff --git a/proxy-server/src/main/java/org/fengfei/lanproxy/server/config/ProxyConfig.java b/proxy-server/src/main/java/org/fengfei/lanproxy/server/config/ProxyConfig.java index 2b817b5..afe66c1 100644 --- a/proxy-server/src/main/java/org/fengfei/lanproxy/server/config/ProxyConfig.java +++ b/proxy-server/src/main/java/org/fengfei/lanproxy/server/config/ProxyConfig.java @@ -1,399 +1,400 @@ -package org.fengfei.lanproxy.server.config; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.fengfei.lanproxy.common.Config; -import org.fengfei.lanproxy.common.JsonUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.gson.reflect.TypeToken; - -/** - * server config - * - * @author fengfei - * - */ -public class ProxyConfig implements Serializable { - - private static final long serialVersionUID = 1L; - - /** 配置文件为config.json */ - public static final String CONFIG_FILE; - - private static Logger logger = LoggerFactory.getLogger(ProxyConfig.class); - - static { - - // 代理配置信息存放在用户根目录下 - String dataPath = System.getProperty("user.home") + "/" + ".lanproxy/"; - File file = new File(dataPath); - if (!file.isDirectory()) { - file.mkdir(); - } - - CONFIG_FILE = dataPath + "/config.json"; - } - - /** 代理服务器绑定主机host */ - private String serverBind; - - /** 代理服务器与代理客户端通信端口 */ - private Integer serverPort; - - /** 配置服务绑定主机host */ - private String configServerBind; - - /** 配置服务端口 */ - private Integer configServerPort; - - /** 配置服务管理员用户名 */ - private String configAdminUsername; - - /** 配置服务管理员密码 */ - private String configAdminPassword; - - /** 代理客户端,支持多个客户端 */ - private List clients; - - /** 更新配置后保证在其他线程即时生效 */ - private static ProxyConfig instance = new ProxyConfig();; - - /** 代理服务器为各个代理客户端(key)开启对应的端口列表(value) */ - private volatile Map> clientInetPortMapping = new HashMap>(); - - /** 代理服务器上的每个对外端口(key)对应的代理客户端背后的真实服务器信息(value) */ - private volatile Map inetPortLanInfoMapping = new HashMap(); - - /** 配置变化监听器 */ - private List configChangedListeners = new ArrayList(); - - private ProxyConfig() { - - // 代理服务器主机和端口配置初始化 - this.serverPort = Config.getInstance().getIntValue("server.port"); - this.serverBind = Config.getInstance().getStringValue("server.bind", "0.0.0.0"); - - // 配置服务器主机和端口配置初始化 - this.configServerPort = Config.getInstance().getIntValue("config.server.port"); - this.configServerBind = Config.getInstance().getStringValue("config.server.bind", "0.0.0.0"); - - // 配置服务器管理员登录认证信息 - this.configAdminUsername = Config.getInstance().getStringValue("config.admin.username"); - this.configAdminPassword = Config.getInstance().getStringValue("config.admin.password"); - - logger.info( - "config init serverBind {}, serverPort {}, configServerBind {}, configServerPort {}, configAdminUsername {}, configAdminPassword {}", - serverBind, serverPort, configServerBind, configServerPort, configAdminUsername, configAdminPassword); - - update(null); - } - - public Integer getServerPort() { - return this.serverPort; - } - - public String getServerBind() { - return serverBind; - } - - public void setServerBind(String serverBind) { - this.serverBind = serverBind; - } - - public String getConfigServerBind() { - return configServerBind; - } - - public void setConfigServerBind(String configServerBind) { - this.configServerBind = configServerBind; - } - - public Integer getConfigServerPort() { - return configServerPort; - } - - public void setConfigServerPort(Integer configServerPort) { - this.configServerPort = configServerPort; - } - - public String getConfigAdminUsername() { - return configAdminUsername; - } - - public void setConfigAdminUsername(String configAdminUsername) { - this.configAdminUsername = configAdminUsername; - } - - public String getConfigAdminPassword() { - return configAdminPassword; - } - - public void setConfigAdminPassword(String configAdminPassword) { - this.configAdminPassword = configAdminPassword; - } - - public void setServerPort(Integer serverPort) { - this.serverPort = serverPort; - } - - public List getClients() { - return clients; - } - - /** - * 解析配置文件 - */ - public void update(String proxyMappingConfigJson) { - - File file = new File(CONFIG_FILE); - try { - if (proxyMappingConfigJson == null && file.exists()) { - InputStream in = new FileInputStream(file); - byte[] buf = new byte[1024]; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - int readIndex; - while ((readIndex = in.read(buf)) != -1) { - out.write(buf, 0, readIndex); - } - - in.close(); - proxyMappingConfigJson = new String(out.toByteArray()); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - - List clients = JsonUtil.json2object(proxyMappingConfigJson, new TypeToken>() { - }); - if (clients == null) { - clients = new ArrayList(); - } - - Map> clientInetPortMapping = new HashMap>(); - Map inetPortLanInfoMapping = new HashMap(); - - // 构造端口映射关系 - for (Client client : clients) { - String clientKey = client.getClientKey(); - if (clientInetPortMapping.containsKey(clientKey)) { - throw new IllegalArgumentException("密钥同时作为客户端标识,不能重复: " + clientKey); - } - List mappings = client.getProxyMappings(); - List ports = new ArrayList(); - clientInetPortMapping.put(clientKey, ports); - for (ClientProxyMapping mapping : mappings) { - Integer port = mapping.getInetPort(); - ports.add(port); - if (inetPortLanInfoMapping.containsKey(port)) { - throw new IllegalArgumentException("一个公网端口只能映射一个后端信息,不能重复: " + port); - } - - inetPortLanInfoMapping.put(port, mapping.getLan()); - } - } - - // 替换之前的配置关系 - this.clientInetPortMapping = clientInetPortMapping; - this.inetPortLanInfoMapping = inetPortLanInfoMapping; - this.clients = clients; - - try { - FileOutputStream out = new FileOutputStream(file); - out.write(proxyMappingConfigJson.getBytes()); - out.flush(); - out.close(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - notifyconfigChangedListeners(); - } - - /** - * 配置更新通知 - */ - private void notifyconfigChangedListeners() { - List changedListeners = new ArrayList(configChangedListeners); - for (ConfigChangedListener changedListener : changedListeners) { - changedListener.onChanged(); - } - } - - /** - * 添加配置变化监听器 - * - * @param configChangedListener - */ - public void addConfigChangedListener(ConfigChangedListener configChangedListener) { - configChangedListeners.add(configChangedListener); - } - - /** - * 移除配置变化监听器 - * - * @param configChangedListener - */ - public void removeConfigChangedListener(ConfigChangedListener configChangedListener) { - configChangedListeners.remove(configChangedListener); - } - - /** - * 获取代理客户端对应的代理服务器端口 - * - * @param clientKey - * @return - */ - public List getClientInetPorts(String clientKey) { - return clientInetPortMapping.get(clientKey); - } - - /** - * 获取所有的clientKey - * - * @return - */ - public Set getClientKeySet() { - return clientInetPortMapping.keySet(); - } - - /** - * 根据代理服务器端口获取后端服务器代理信息 - * - * @param port - * @return - */ - public String getLanInfo(Integer port) { - return inetPortLanInfoMapping.get(port); - } - - /** - * 返回需要绑定在代理服务器的端口(用于用户请求) - * - * @return - */ - public List getUserPorts() { - List ports = new ArrayList(); - Iterator ite = inetPortLanInfoMapping.keySet().iterator(); - while (ite.hasNext()) { - ports.add(ite.next()); - } - - return ports; - } - - public static ProxyConfig getInstance() { - return instance; - } - - /** - * 代理客户端 - * - * @author fengfei - * - */ - public static class Client implements Serializable { - - private static final long serialVersionUID = 1L; - - /** 客户端备注名称 */ - private String name; - - /** 代理客户端唯一标识key */ - private String clientKey; - - /** 代理客户端与其后面的真实服务器映射关系 */ - private List proxyMappings; - - public String getClientKey() { - return clientKey; - } - - public void setClientKey(String clientKey) { - this.clientKey = clientKey; - } - - public List getProxyMappings() { - return proxyMappings; - } - - public void setProxyMappings(List proxyMappings) { - this.proxyMappings = proxyMappings; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - } - - /** - * 代理客户端与其后面真实服务器映射关系 - * - * @author fengfei - * - */ - public static class ClientProxyMapping { - - /** 代理服务器端口 */ - private Integer inetPort; - - /** 需要代理的网络信息(代理客户端能够访问),格式 192.168.1.99:80 (必须带端口) */ - private String lan; - - /** 备注名称 */ - private String name; - - public Integer getInetPort() { - return inetPort; - } - - public void setInetPort(Integer inetPort) { - this.inetPort = inetPort; - } - - public String getLan() { - return lan; - } - - public void setLan(String lan) { - this.lan = lan; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - } - - /** - * 配置更新回调 - * - * @author fengfei - * - */ - public static interface ConfigChangedListener { - - void onChanged(); - } -} +package org.fengfei.lanproxy.server.config; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.Serializable; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.fengfei.lanproxy.common.Config; +import org.fengfei.lanproxy.common.JsonUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.reflect.TypeToken; + +/** + * server config + * + * @author fengfei + * + */ +public class ProxyConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 配置文件为config.json */ + public static final String CONFIG_FILE; + + private static Logger logger = LoggerFactory.getLogger(ProxyConfig.class); + + static { + + // 代理配置信息存放在用户根目录下 + String dataPath = System.getProperty("user.home") + "/" + ".lanproxy/"; + File file = new File(dataPath); + if (!file.isDirectory()) { + file.mkdir(); + } + + CONFIG_FILE = dataPath + "/config.json"; + } + + /** 代理服务器绑定主机host */ + private String serverBind; + + /** 代理服务器与代理客户端通信端口 */ + private Integer serverPort; + + /** 配置服务绑定主机host */ + private String configServerBind; + + /** 配置服务端口 */ + private Integer configServerPort; + + /** 配置服务管理员用户名 */ + private String configAdminUsername; + + /** 配置服务管理员密码 */ + private String configAdminPassword; + + /** 代理客户端,支持多个客户端 */ + private List clients; + + /** 更新配置后保证在其他线程即时生效 */ + private static ProxyConfig instance = new ProxyConfig();; + + /** 代理服务器为各个代理客户端(key)开启对应的端口列表(value) */ + private volatile Map> clientInetPortMapping = new HashMap>(); + + /** 代理服务器上的每个对外端口(key)对应的代理客户端背后的真实服务器信息(value) */ + private volatile Map inetPortLanInfoMapping = new HashMap(); + + /** 配置变化监听器 */ + private List configChangedListeners = new ArrayList(); + + private ProxyConfig() { + + // 代理服务器主机和端口配置初始化 + this.serverPort = Config.getInstance().getIntValue("server.port"); + this.serverBind = Config.getInstance().getStringValue("server.bind", "0.0.0.0"); + + // 配置服务器主机和端口配置初始化 + this.configServerPort = Config.getInstance().getIntValue("config.server.port"); + this.configServerBind = Config.getInstance().getStringValue("config.server.bind", "0.0.0.0"); + + // 配置服务器管理员登录认证信息 + this.configAdminUsername = Config.getInstance().getStringValue("config.admin.username"); + this.configAdminPassword = Config.getInstance().getStringValue("config.admin.password"); + + logger.info( + "config init serverBind {}, serverPort {}, configServerBind {}, configServerPort {}, configAdminUsername {}, configAdminPassword {}", + serverBind, serverPort, configServerBind, configServerPort, configAdminUsername, configAdminPassword); + + update(null); + } + + public Integer getServerPort() { + return this.serverPort; + } + + public String getServerBind() { + return serverBind; + } + + public void setServerBind(String serverBind) { + this.serverBind = serverBind; + } + + public String getConfigServerBind() { + return configServerBind; + } + + public void setConfigServerBind(String configServerBind) { + this.configServerBind = configServerBind; + } + + public Integer getConfigServerPort() { + return configServerPort; + } + + public void setConfigServerPort(Integer configServerPort) { + this.configServerPort = configServerPort; + } + + public String getConfigAdminUsername() { + return configAdminUsername; + } + + public void setConfigAdminUsername(String configAdminUsername) { + this.configAdminUsername = configAdminUsername; + } + + public String getConfigAdminPassword() { + return configAdminPassword; + } + + public void setConfigAdminPassword(String configAdminPassword) { + this.configAdminPassword = configAdminPassword; + } + + public void setServerPort(Integer serverPort) { + this.serverPort = serverPort; + } + + public List getClients() { + return clients; + } + + /** + * 解析配置文件 + */ + public void update(String proxyMappingConfigJson) { + + File file = new File(CONFIG_FILE); + try { + if (proxyMappingConfigJson == null && file.exists()) { + InputStream in = new FileInputStream(file); + byte[] buf = new byte[1024]; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int readIndex; + while ((readIndex = in.read(buf)) != -1) { + out.write(buf, 0, readIndex); + } + + in.close(); + proxyMappingConfigJson = new String(out.toByteArray(), Charset.forName("UTF-8")); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + + List clients = JsonUtil.json2object(proxyMappingConfigJson, new TypeToken>() { + }); + if (clients == null) { + clients = new ArrayList(); + } + + Map> clientInetPortMapping = new HashMap>(); + Map inetPortLanInfoMapping = new HashMap(); + + // 构造端口映射关系 + for (Client client : clients) { + String clientKey = client.getClientKey(); + if (clientInetPortMapping.containsKey(clientKey)) { + throw new IllegalArgumentException("密钥同时作为客户端标识,不能重复: " + clientKey); + } + List mappings = client.getProxyMappings(); + List ports = new ArrayList(); + clientInetPortMapping.put(clientKey, ports); + for (ClientProxyMapping mapping : mappings) { + Integer port = mapping.getInetPort(); + ports.add(port); + if (inetPortLanInfoMapping.containsKey(port)) { + throw new IllegalArgumentException("一个公网端口只能映射一个后端信息,不能重复: " + port); + } + + inetPortLanInfoMapping.put(port, mapping.getLan()); + } + } + + // 替换之前的配置关系 + this.clientInetPortMapping = clientInetPortMapping; + this.inetPortLanInfoMapping = inetPortLanInfoMapping; + this.clients = clients; + + try { + FileOutputStream out = new FileOutputStream(file); + out.write(proxyMappingConfigJson.getBytes(Charset.forName("UTF-8"))); + out.flush(); + out.close(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + notifyconfigChangedListeners(); + } + + /** + * 配置更新通知 + */ + private void notifyconfigChangedListeners() { + List changedListeners = new ArrayList(configChangedListeners); + for (ConfigChangedListener changedListener : changedListeners) { + changedListener.onChanged(); + } + } + + /** + * 添加配置变化监听器 + * + * @param configChangedListener + */ + public void addConfigChangedListener(ConfigChangedListener configChangedListener) { + configChangedListeners.add(configChangedListener); + } + + /** + * 移除配置变化监听器 + * + * @param configChangedListener + */ + public void removeConfigChangedListener(ConfigChangedListener configChangedListener) { + configChangedListeners.remove(configChangedListener); + } + + /** + * 获取代理客户端对应的代理服务器端口 + * + * @param clientKey + * @return + */ + public List getClientInetPorts(String clientKey) { + return clientInetPortMapping.get(clientKey); + } + + /** + * 获取所有的clientKey + * + * @return + */ + public Set getClientKeySet() { + return clientInetPortMapping.keySet(); + } + + /** + * 根据代理服务器端口获取后端服务器代理信息 + * + * @param port + * @return + */ + public String getLanInfo(Integer port) { + return inetPortLanInfoMapping.get(port); + } + + /** + * 返回需要绑定在代理服务器的端口(用于用户请求) + * + * @return + */ + public List getUserPorts() { + List ports = new ArrayList(); + Iterator ite = inetPortLanInfoMapping.keySet().iterator(); + while (ite.hasNext()) { + ports.add(ite.next()); + } + + return ports; + } + + public static ProxyConfig getInstance() { + return instance; + } + + /** + * 代理客户端 + * + * @author fengfei + * + */ + public static class Client implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 客户端备注名称 */ + private String name; + + /** 代理客户端唯一标识key */ + private String clientKey; + + /** 代理客户端与其后面的真实服务器映射关系 */ + private List proxyMappings; + + public String getClientKey() { + return clientKey; + } + + public void setClientKey(String clientKey) { + this.clientKey = clientKey; + } + + public List getProxyMappings() { + return proxyMappings; + } + + public void setProxyMappings(List proxyMappings) { + this.proxyMappings = proxyMappings; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + } + + /** + * 代理客户端与其后面真实服务器映射关系 + * + * @author fengfei + * + */ + public static class ClientProxyMapping { + + /** 代理服务器端口 */ + private Integer inetPort; + + /** 需要代理的网络信息(代理客户端能够访问),格式 192.168.1.99:80 (必须带端口) */ + private String lan; + + /** 备注名称 */ + private String name; + + public Integer getInetPort() { + return inetPort; + } + + public void setInetPort(Integer inetPort) { + this.inetPort = inetPort; + } + + public String getLan() { + return lan; + } + + public void setLan(String lan) { + this.lan = lan; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + } + + /** + * 配置更新回调 + * + * @author fengfei + * + */ + public static interface ConfigChangedListener { + + void onChanged(); + } +} diff --git a/proxy-server/src/main/java/org/fengfei/lanproxy/server/config/web/routes/RouteConfig.java b/proxy-server/src/main/java/org/fengfei/lanproxy/server/config/web/routes/RouteConfig.java index a90cfb6..700b941 100644 --- a/proxy-server/src/main/java/org/fengfei/lanproxy/server/config/web/routes/RouteConfig.java +++ b/proxy-server/src/main/java/org/fengfei/lanproxy/server/config/web/routes/RouteConfig.java @@ -1,164 +1,167 @@ -package org.fengfei.lanproxy.server.config.web.routes; - -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.fengfei.lanproxy.common.JsonUtil; -import org.fengfei.lanproxy.server.config.ProxyConfig; -import org.fengfei.lanproxy.server.config.ProxyConfig.Client; -import org.fengfei.lanproxy.server.config.web.ApiRoute; -import org.fengfei.lanproxy.server.config.web.RequestHandler; -import org.fengfei.lanproxy.server.config.web.RequestMiddleware; -import org.fengfei.lanproxy.server.config.web.ResponseInfo; -import org.fengfei.lanproxy.server.config.web.exception.ContextException; -import org.fengfei.lanproxy.server.metrics.MetricsCollector; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.gson.reflect.TypeToken; - -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.HttpHeaders; - -/** - * 接口实现 - * - * @author fengfei - * - */ -public class RouteConfig { - - protected static final String AUTH_COOKIE_KEY = "token"; - - private static Logger logger = LoggerFactory.getLogger(RouteConfig.class); - - /** 管理员不能同时在多个地方登录 */ - private static String token; - - public static void init() { - - ApiRoute.addMiddleware(new RequestMiddleware() { - - @Override - public void preRequest(FullHttpRequest request) { - String cookieHeader = request.headers().get(HttpHeaders.Names.COOKIE); - boolean authenticated = false; - if (cookieHeader != null) { - String[] cookies = cookieHeader.split(";"); - for (String cookie : cookies) { - String[] cookieArr = cookie.split("="); - if (AUTH_COOKIE_KEY.equals(cookieArr[0].trim())) { - if (cookieArr.length == 2 && cookieArr[1].equals(token)) { - authenticated = true; - } - } - } - } - - String auth = request.headers().get(HttpHeaders.Names.AUTHORIZATION); - if (!authenticated && auth != null) { - String[] authArr = auth.split(" "); - if (authArr.length == 2 && authArr[0].equals(ProxyConfig.getInstance().getConfigAdminUsername()) && authArr[1].equals(ProxyConfig.getInstance().getConfigAdminPassword())) { - authenticated = true; - } - } - - if (!request.getUri().equals("/login") && !authenticated) { - throw new ContextException(ResponseInfo.CODE_UNAUTHORIZED); - } - - logger.info("handle request for api {}", request.getUri()); - } - }); - - // 获取配置详细信息 - ApiRoute.addRoute("/config/detail", new RequestHandler() { - - @Override - public ResponseInfo request(FullHttpRequest request) { - - return ResponseInfo.build(ProxyConfig.getInstance().getClients()); - } - }); - - // 更新配置 - ApiRoute.addRoute("/config/update", new RequestHandler() { - - @Override - public ResponseInfo request(FullHttpRequest request) { - byte[] buf = new byte[request.content().readableBytes()]; - request.content().readBytes(buf); - String config = new String(buf); - List clients = JsonUtil.json2object(config, new TypeToken>() { - }); - if (clients == null) { - return ResponseInfo.build(ResponseInfo.CODE_INVILID_PARAMS, "Error json config"); - } - - try { - ProxyConfig.getInstance().update(config); - } catch (Exception ex) { - logger.error("config update error", ex); - return ResponseInfo.build(ResponseInfo.CODE_INVILID_PARAMS, ex.getMessage()); - } - - return ResponseInfo.build(ResponseInfo.CODE_OK, "success"); - } - }); - - ApiRoute.addRoute("/login", new RequestHandler() { - - @Override - public ResponseInfo request(FullHttpRequest request) { - byte[] buf = new byte[request.content().readableBytes()]; - request.content().readBytes(buf); - String config = new String(buf); - Map loginParams = JsonUtil.json2object(config, new TypeToken>() { - }); - if (loginParams == null) { - return ResponseInfo.build(ResponseInfo.CODE_INVILID_PARAMS, "Error login info"); - } - - String username = loginParams.get("username"); - String password = loginParams.get("password"); - if (username == null || password == null) { - return ResponseInfo.build(ResponseInfo.CODE_INVILID_PARAMS, "Error username or password"); - } - - if (username.equals(ProxyConfig.getInstance().getConfigAdminUsername()) && password.equals(ProxyConfig.getInstance().getConfigAdminPassword())) { - token = UUID.randomUUID().toString().replace("-", ""); - return ResponseInfo.build(token); - } - - return ResponseInfo.build(ResponseInfo.CODE_INVILID_PARAMS, "Error username or password"); - } - }); - - ApiRoute.addRoute("/logout", new RequestHandler() { - - @Override - public ResponseInfo request(FullHttpRequest request) { - token = null; - return ResponseInfo.build(ResponseInfo.CODE_OK, "success"); - } - }); - - ApiRoute.addRoute("/metrics/get", new RequestHandler() { - - @Override - public ResponseInfo request(FullHttpRequest request) { - return ResponseInfo.build(MetricsCollector.getAllMetrics()); - } - }); - - ApiRoute.addRoute("/metrics/getandreset", new RequestHandler() { - - @Override - public ResponseInfo request(FullHttpRequest request) { - return ResponseInfo.build(MetricsCollector.getAndResetAllMetrics()); - } - }); - } - -} +package org.fengfei.lanproxy.server.config.web.routes; + +import java.nio.charset.Charset; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.fengfei.lanproxy.common.JsonUtil; +import org.fengfei.lanproxy.server.config.ProxyConfig; +import org.fengfei.lanproxy.server.config.ProxyConfig.Client; +import org.fengfei.lanproxy.server.config.web.ApiRoute; +import org.fengfei.lanproxy.server.config.web.RequestHandler; +import org.fengfei.lanproxy.server.config.web.RequestMiddleware; +import org.fengfei.lanproxy.server.config.web.ResponseInfo; +import org.fengfei.lanproxy.server.config.web.exception.ContextException; +import org.fengfei.lanproxy.server.metrics.MetricsCollector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.reflect.TypeToken; + +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpHeaders; + +/** + * 接口实现 + * + * @author fengfei + * + */ +public class RouteConfig { + + protected static final String AUTH_COOKIE_KEY = "token"; + + private static Logger logger = LoggerFactory.getLogger(RouteConfig.class); + + /** 管理员不能同时在多个地方登录 */ + private static String token; + + public static void init() { + + ApiRoute.addMiddleware(new RequestMiddleware() { + + @Override + public void preRequest(FullHttpRequest request) { + String cookieHeader = request.headers().get(HttpHeaders.Names.COOKIE); + boolean authenticated = false; + if (cookieHeader != null) { + String[] cookies = cookieHeader.split(";"); + for (String cookie : cookies) { + String[] cookieArr = cookie.split("="); + if (AUTH_COOKIE_KEY.equals(cookieArr[0].trim())) { + if (cookieArr.length == 2 && cookieArr[1].equals(token)) { + authenticated = true; + } + } + } + } + + String auth = request.headers().get(HttpHeaders.Names.AUTHORIZATION); + if (!authenticated && auth != null) { + String[] authArr = auth.split(" "); + if (authArr.length == 2 && authArr[0].equals(ProxyConfig.getInstance().getConfigAdminUsername()) + && authArr[1].equals(ProxyConfig.getInstance().getConfigAdminPassword())) { + authenticated = true; + } + } + + if (!request.getUri().equals("/login") && !authenticated) { + throw new ContextException(ResponseInfo.CODE_UNAUTHORIZED); + } + + logger.info("handle request for api {}", request.getUri()); + } + }); + + // 获取配置详细信息 + ApiRoute.addRoute("/config/detail", new RequestHandler() { + + @Override + public ResponseInfo request(FullHttpRequest request) { + + return ResponseInfo.build(ProxyConfig.getInstance().getClients()); + } + }); + + // 更新配置 + ApiRoute.addRoute("/config/update", new RequestHandler() { + + @Override + public ResponseInfo request(FullHttpRequest request) { + byte[] buf = new byte[request.content().readableBytes()]; + request.content().readBytes(buf); + String config = new String(buf, Charset.forName("UTF-8")); + List clients = JsonUtil.json2object(config, new TypeToken>() { + }); + if (clients == null) { + return ResponseInfo.build(ResponseInfo.CODE_INVILID_PARAMS, "Error json config"); + } + + try { + ProxyConfig.getInstance().update(config); + } catch (Exception ex) { + logger.error("config update error", ex); + return ResponseInfo.build(ResponseInfo.CODE_INVILID_PARAMS, ex.getMessage()); + } + + return ResponseInfo.build(ResponseInfo.CODE_OK, "success"); + } + }); + + ApiRoute.addRoute("/login", new RequestHandler() { + + @Override + public ResponseInfo request(FullHttpRequest request) { + byte[] buf = new byte[request.content().readableBytes()]; + request.content().readBytes(buf); + String config = new String(buf); + Map loginParams = JsonUtil.json2object(config, new TypeToken>() { + }); + if (loginParams == null) { + return ResponseInfo.build(ResponseInfo.CODE_INVILID_PARAMS, "Error login info"); + } + + String username = loginParams.get("username"); + String password = loginParams.get("password"); + if (username == null || password == null) { + return ResponseInfo.build(ResponseInfo.CODE_INVILID_PARAMS, "Error username or password"); + } + + if (username.equals(ProxyConfig.getInstance().getConfigAdminUsername()) + && password.equals(ProxyConfig.getInstance().getConfigAdminPassword())) { + token = UUID.randomUUID().toString().replace("-", ""); + return ResponseInfo.build(token); + } + + return ResponseInfo.build(ResponseInfo.CODE_INVILID_PARAMS, "Error username or password"); + } + }); + + ApiRoute.addRoute("/logout", new RequestHandler() { + + @Override + public ResponseInfo request(FullHttpRequest request) { + token = null; + return ResponseInfo.build(ResponseInfo.CODE_OK, "success"); + } + }); + + ApiRoute.addRoute("/metrics/get", new RequestHandler() { + + @Override + public ResponseInfo request(FullHttpRequest request) { + return ResponseInfo.build(MetricsCollector.getAllMetrics()); + } + }); + + ApiRoute.addRoute("/metrics/getandreset", new RequestHandler() { + + @Override + public ResponseInfo request(FullHttpRequest request) { + return ResponseInfo.build(MetricsCollector.getAndResetAllMetrics()); + } + }); + } + +} diff --git a/proxy-server/src/test/resources/config.properties b/proxy-server/src/test/resources/config.properties index 7ff2c85..1ac6c79 100644 --- a/proxy-server/src/test/resources/config.properties +++ b/proxy-server/src/test/resources/config.properties @@ -1,15 +1,15 @@ -server.bind=0.0.0.0 -server.port=4900 - -server.ssl.enable=true -server.ssl.bind=0.0.0.0 -server.ssl.port=4993 -server.ssl.jksPath=test.jks -server.ssl.keyStorePassword=123456 -server.ssl.keyManagerPassword=123456 -server.ssl.needsClientAuth=false - -config.server.bind=0.0.0.0 -config.server.port=8082 -config.admin.username=admin +server.bind=0.0.0.0 +server.port=4900 + +server.ssl.enable=true +server.ssl.bind=0.0.0.0 +server.ssl.port=4993 +server.ssl.jksPath=test.jks +server.ssl.keyStorePassword=123456 +server.ssl.keyManagerPassword=123456 +server.ssl.needsClientAuth=false + +config.server.bind=0.0.0.0 +config.server.port=8090 +config.admin.username=admin config.admin.password=admin \ No newline at end of file