Commit e44f3e93 authored by howard Lee's avatar howard Lee

微服务本地测试提交1

parent 02176e48
......@@ -3,3 +3,6 @@
start "授权服务器" java -jar -Xmx300m configserverSR.jar
mvn clean package
http://localhost:1112/demo/dev
\ No newline at end of file
......@@ -7,15 +7,15 @@ spring:
git:
uri: http://106.14.62.141:8081/serviceu/config-repo.git
rabbitmq:
# virtual-host: /config
host: 192.168.6.28
virtual-host: /config
host: 192.168.8.31
port: 5672
username: howard
password: 123
security:
user:
name: sinra
password: mobiledev
name: test
password: test
server:
port: 1112
eureka:
......@@ -23,7 +23,7 @@ eureka:
prefer-ip-address: true
client:
serviceUrl:
defaultZone: http://sinra:mobiledev@192.168.8.31:1110/eureka/
defaultZone: http://test:test@127.0.0.1:1110/eureka/
management:
endpoints:
web:
......
/target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
\ No newline at end of file
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Migwn, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
echo $MAVEN_PROJECTBASEDIR
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.leedarson</groupId>
<artifactId>ldszuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ldszuul</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1 在编写filter的时候,注意filter的顺序,不然里面的属性会被其他的filter覆盖,比如控制路由跳转会被PreDecorationFilter覆盖
2 具体的内容可以阅读源码。
3
经过测试,所有访问这个路由地址的请求,只有在application.yml中已经匹配到了路径的,才会触发拦截器。7也就是说,在我们定制的和已知的拦截器之前,
就已经有一个过滤请求性质的东西了。
Zuul RequestContext
To pass information between filters, Zuul uses a RequestContext. Its data is held in a ThreadLocal specific to each request.
Information about where to route requests, errors, and the actual HttpServletRequest and HttpServletResponse are stored there.
The RequestContext extends ConcurrentHashMap, so anything can be stored in the context.
FilterConstants contains the keys used by the filters installed by Spring Cloud Netflix (more on these later).
zuul过滤器的几点说明
过滤器类型分为三种, Pre Filter , Route Filter , Post Filter
Pre filters set up data in the RequestContext for use in filters downstream.
The main use case is to set information required for route filters.
Route filters run after pre filters and make requests to other services.
Much of the work here is to translate request and response data to and from the model required by the client.
Post filters typically manipulate the response.
超时的配置
经过实际测试得出,
ribbon:
eager-load:
enabled: true
ConnectTimeout: 3000
ReadTimeout: 25000
这里的是在使用eureka下起作用的配置,出此之外其他的配置不起作用,但是最好吃与这里配置一致。
start "动态路由" java -jar -Dspring.profiles.active=dev -Xmx300m ldszuul.jar
增加了yml的profiles之后需要在mvn命令后携带参数,已传递给TEST模块进行测试。
mvn clean package -Dspring.profiles.active=prod
\ No newline at end of file
package com.leedarson;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UrlPathHelper;
import com.netflix.util.Pair;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.http.HttpServletRequestWrapper;
/**
* <del> 用以对CAS单点登陆的辅助过滤器,顺序排在decoration之后,主要的工作就是截取需要CAS授权的请求,
* 然后转发到该请求至目标服务,再在目标服务成功授权之后,把该请求发回到目标服务,因为cas路由得属性strip-prefix是false,因此不会被
* 截取掉路径里面的任何字符串,能够保证地址栏始终一直符合cas的要求,再加上能根据地址第二位获得转发项目,这样所有项目都可以共用这个路由服务<br>
* </del>
* 推翻了第一版本的设计,原因是在部署分布式的情况下,cas登陆成功后后跳转回来的地址指向的那个服务器,并不一定是最开始向cas发送请求的服务器。找了一下也没有让zuul
* 手动选择具体url的办法,zuul跳转到具体URL使用的是ribbon的负载均衡本身不直接处理url,因此只能放弃固定某一个服务客户端负责cas的思路,因此只能把cas功能抽象出来
* 单独处理所有项目的CAS请求。
*
* @author howard
* @Create_Date: 2018年8月9日下午5:22:08
* @Modified_By: howard
* @Modified_Date: 2018年10月9日下午6:48:52
* @Why_and_What_is_modified: <br>
*/
@Component
public class CasAuthPreFilter extends ZuulFilter {
static Logger log = LoggerFactory.getLogger(CasAuthPreFilter.class);
@Override
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER + 1; // run after
// PreDecoration
// return FilterConstants.SEND_FORWARD_FILTER_ORDER;
}
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Autowired
private RouteLocator routeLocator;
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
// return !ctx.containsKey(FilterConstants.FORWARD_TO_KEY) // a filter has
// // already forwarded
// && !ctx.containsKey(FilterConstants.SERVICE_ID_KEY); // a filter has already
// // determined serviceId
UrlPathHelper h = new UrlPathHelper();
final String requestURI = h.getPathWithinApplication(ctx.getRequest());
Route matchingRoute = routeLocator.getMatchingRoute(requestURI);
String routerId = matchingRoute.getId();
if (StringUtils.equals(routerId, "cas")) {
return true;
} else {
return false;
}
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
UrlPathHelper h = new UrlPathHelper();
HttpServletRequest request = ctx.getRequest();
// final String requestURI = h.getPathWithinApplication(ctx.getRequest());
// String contextPath = request.getContextPath();
// String localAddr = request.getLocalAddr();
// String scheme = request.getScheme();
// String remoteHost = request.getRemoteHost();
// String requestURI2 = request.getRequestURI();
// StringBuffer requestURL = request.getRequestURL();
// HttpServletResponse response = ctx.getResponse();
// 获取不到,通过阅读源码发现,这里需要在指定routhost为http或者https的时候,会被显示的设置地址。
// try {
// URI uri2 = ctx.getRouteHost().toURI();
// } catch (URISyntaxException e1) {
// e1.printStackTrace();
// }
// 这个方法的作用,是获得当前,微服务所有已经注册了的服务的路由信息
// 吧已经注册了的casserver服务器加进来。
List<Route> routes = routeLocator.getRoutes();
HashSet<String> casServerSet = new java.util.HashSet();
// casServerSet.add("ldscasserver2");
routes.forEach(r -> {
String id = r.getId();
if (StringUtils.contains(id, "ldscasserver")) {
casServerSet.add(id);
}
});
// 模拟进行随机授权服务器的负载均衡
Object[] array = casServerSet.toArray();
if (array.length > 0) {
String cookieName = "McloudOAuth";
String McloudOAuth = getCookie(request, cookieName);
if (StringUtils.isNoneBlank(McloudOAuth)) {
// 存在cookies需要做的事情待办
}
String urlkey = ctx.get(FilterConstants.REQUEST_URI_KEY).toString();
if (StringUtils.contains(urlkey, "/ldscasserver")) {
// 已经是从casserver到cas服务器的请求返回casserver
// 截取到目标的casserver
String remove = StringUtils.remove(urlkey, "/cas/");
String serviceId = StringUtils.substringBefore(remove, "/");
log.info("====================================选用的CAS服务ID为 :" + serviceId);
ctx.remove("routeHost");
ctx.put(FilterConstants.SERVICE_ID_KEY, serviceId);
} else {
Random random = new Random();
int nextInt = random.nextInt(array.length);
String serviceId = array[nextInt].toString();
// 上面这个就是这次选定使用的CAS服务
String removeFirst = StringUtils.removeFirst(urlkey, "/cas/");
removeFirst = "/cas/" + serviceId + "/" + removeFirst;
// 更改访问的url,应该把地址改下?
// 据说是为了防止后续的一个简单过滤器运行
ctx.remove("routeHost");
ctx.put(FilterConstants.SERVICE_ID_KEY, serviceId);
ctx.put(FilterConstants.REQUEST_URI_KEY, removeFirst);
}
} else {
// 没有注册服务器,就只有报错了
log.error("用户使用CAS授权,在为服务中却没有发现已经注册的cas服务器。");
}
// Route matchingRoute = routeLocator.getMatchingRoute(requestURI);
// String routerId = matchingRoute.getId();
// if (StringUtils.equals(routerId, "cas")) {
// log.debug("符合CAS路由,开始根据后缀判断提供的服务项目");
// if (StringUtils.startsWith(requestURI, "/cas/")) {
// // 尝试增加判断
// // 放弃,无法改变访问地址URL
// HttpServletRequest request = ctx.getRequest();
// String cookieName = "McloudOAuth";
// String McloudOAuth = getCookie(request, cookieName);
// //
// if (StringUtils.isNoneBlank(McloudOAuth)) {
// // 如果已经有了缓存,不做任何处理,继续往下走。再SSO的拦截器中会避免向授权服务器发送请求
// // 如果cookie不为空,则尝试改变路径,直接匹配到m/mco里去
// String uri = request.getRequestURI();
// // return null;
// Object originalRequestPath = ctx.get(FilterConstants.REQUEST_URI_KEY);
//
// }
// // 属于CAS单点登陆
// // 通过截取地址栏,获得应该跳转的服务地址
// String remove = StringUtils.remove(requestURI, "/cas/");
//
//
// }
// }
return null;
}
// public static void main(String[] args) {
// HashSet<String> set = new HashSet<>();
// set.add("s1");
// set.add("s2");
// set.add("s3");
// set.add("s4");
// Object[] array = set.toArray();
// for (int i = 0; i < 10; i++) {
// if (array.length > 0) {
// Random random = new Random();
// int nextInt = random.nextInt(array.length);
// System.out.println(array[nextInt]);
// }
// }
// }
/**
* 获得指定Cookie的值
*
* @param name
* 名称
* @return 值
*/
public static String getCookie(HttpServletRequest request, String name) {
String userName = getCookie(request, null, name, false);
if (StringUtils.isBlank(userName)) {
return null;
} else {
int index = userName.indexOf("@@");
if (index == -1) {
return userName;
} else {
return userName.substring(0, index);
}
}
}
/**
* 获得指定Cookie的值
*
* @param request
* 请求对象
* @param response
* 响应对象
* @param name
* 名字
* @param isRemove
* 是否移除
* @return 值
*/
public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name,
boolean isRemove) {
String value = null;
Cookie[] cookies = request.getCookies();
log.debug("get cookies is" + ArrayUtils.toString(cookies));
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(name)) {
try {
value = URLDecoder.decode(cookie.getValue(), StandardCharsets.UTF_8.name());
// break;
} catch (Exception e) {
log.error("cookie解码失败:" + cookie.getValue());
e.printStackTrace();
}
if (isRemove) {
cookie.setMaxAge(0);
// if
// (StringUtils.isNotBlank(SpringContextHolder.getApplicationContext().getApplicationName()))
// {
// cookie.setPath(SpringContextHolder.getApplicationContext().getApplicationName());
// } else {
// cookie.setPath("/");
// }
cookie.setPath("/");
log.debug("开始设置COOKIE:name is " + name + " value is " + value + " setMaxAge is 0");
response.addCookie(cookie);
}
}
}
}
return value;
}
public static void setCookie(HttpServletResponse response, String name, String value, int maxAge) {
Cookie cookie = new Cookie(name, null);
// if
// (StringUtils.isNotBlank(SpringContextHolder.getApplicationContext().getApplicationName()))
// {
// cookie.setPath(SpringContextHolder.getApplicationContext().getApplicationName());
// } else {
// cookie.setPath("/");
// }
cookie.setPath("/");
cookie.setMaxAge(maxAge);
try {
if (StringUtils.isNotEmpty(value)) {
cookie.setValue(URLEncoder.encode(value, "utf-8"));
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
log.debug("开始设置COOKIE:name is " + name + " value is " + value);
response.addCookie(cookie);
}
}
package com.leedarson;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UrlPathHelper;
import com.netflix.util.Pair;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.http.HttpServletRequestWrapper;
/**
* <del> 用以对CAS单点登陆的辅助过滤器,顺序排在decoration之后,主要的工作就是截取需要CAS授权的请求,
* 然后转发到该请求至目标服务,再在目标服务成功授权之后,把该请求发回到目标服务,因为cas路由得属性strip-prefix是false,因此不会被
* 截取掉路径里面的任何字符串,能够保证地址栏始终一直符合cas的要求,再加上能根据地址第二位获得转发项目,这样所有项目都可以共用这个路由服务<br>
* </del>
* 推翻了第一版本的设计,原因是在部署分布式的情况下,cas登陆成功后后跳转回来的地址指向的那个服务器,并不一定是最开始向cas发送请求的服务器。找了一下也没有让zuul
* 手动选择具体url的办法,zuul跳转到具体URL使用的是ribbon的负载均衡本身不直接处理url,因此只能放弃固定某一个服务客户端负责cas的思路,因此只能把cas功能抽象出来
* 单独处理所有项目的CAS请求。
*
* @author howard
* @Create_Date: 2018年8月9日下午5:22:08
* @Modified_By: howard
* @Modified_Date: 2018年10月9日下午6:48:52
* @Why_and_What_is_modified: <br>
*/
// @Component
public class CasAuthPreFilterBAK extends ZuulFilter {
static Logger log = LoggerFactory.getLogger(CasAuthPreFilterBAK.class);
@Override
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER + 1; // run after
// PreDecoration
// return FilterConstants.SEND_FORWARD_FILTER_ORDER;
}
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Autowired
private RouteLocator routeLocator;
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
// return !ctx.containsKey(FilterConstants.FORWARD_TO_KEY) // a filter has
// // already forwarded
// && !ctx.containsKey(FilterConstants.SERVICE_ID_KEY); // a filter has already
// // determined serviceId
UrlPathHelper h = new UrlPathHelper();
final String requestURI = h.getPathWithinApplication(ctx.getRequest());
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
UrlPathHelper h = new UrlPathHelper();
final String requestURI = h.getPathWithinApplication(ctx.getRequest());
// HttpServletResponse response = ctx.getResponse();
// 获取不到,通过阅读源码发现,这里需要在指定routhost为http或者https的时候,会被显示的设置地址。
// try {
// URI uri2 = ctx.getRouteHost().toURI();
// } catch (URISyntaxException e1) {
// e1.printStackTrace();
// }
List<Route> routes = routeLocator.getRoutes();
routes.forEach(r -> {
System.out.println(r.getFullPath());
System.out.println(r.getId());
System.out.println(r.getLocation());
System.out.println(r.getPath());
System.out.println(r.getPrefix());
});
Route matchingRoute = routeLocator.getMatchingRoute(requestURI);
String routerId = matchingRoute.getId();
if (StringUtils.equals(routerId, "cas")) {
log.debug("符合CAS路由,开始根据后缀判断提供的服务项目");
if (StringUtils.startsWith(requestURI, "/cas/")) {
// 尝试增加判断
// 放弃,无法改变访问地址URL
HttpServletRequest request = ctx.getRequest();
String cookieName = "McloudOAuth";
String McloudOAuth = getCookie(request, cookieName);
// 尝试进行head的注入,用来产生识别标识,发现这些哪怕设置进去也无法作用于 CAS的重定向
// Object object = ctx.get("ctxset");
// Object object2 = ctx.get("ctxput");
// List<Pair<String, String>> originResponseHeaders =
// ctx.getOriginResponseHeaders();
// Map<String, String> zuulRequestHeaders = ctx.getZuulRequestHeaders();
// List<Pair<String, String>> zuulResponseHeaders =
// ctx.getZuulResponseHeaders();
// // 手动增加标识
// ctx.set("ctxset", "ctxset");
// ctx.put("ctxput", "ctx.put");
// ctx.addZuulRequestHeader("addZuulRequestHeader", "addZuulRequestHeader");
// ctx.addOriginResponseHeader("addOriginResponseHeader",
// "addOriginResponseHeader");
//
URL url = null;
try {
URI uri = ctx.getRouteHost().toURI();
int port = ctx.getRouteHost().getPort();
url = UriComponentsBuilder.fromUri(uri).port(port).build().toUri().toURL();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
// ctx.setRouteHost(url);
//
if (StringUtils.isNoneBlank(McloudOAuth)) {
// 如果已经有了缓存,不做任何处理,继续往下走。再SSO的拦截器中会避免向授权服务器发送请求
// 如果cookie不为空,则尝试改变路径,直接匹配到m/mco里去
String uri = request.getRequestURI();
String responseBody = ctx.getResponseBody();
// System.out.println(responseBody);
// // new request
// HttpServletRequestWrapper httpServletRequestWrapper = new
// HttpServletRequestWrapper(request) {
//
// @Override
// public Enumeration<String> getHeaderNames() {
// return super.getHeaderNames();
// }
//
// @Override
// public StringBuffer getRequestURL() {
// String string = super.getRequestURL().toString();
// string = StringUtils.replace(string, "cas/mobile3/f", "mobile3/mco/f");
// StringBuffer sb = new StringBuffer(string);
// System.out.println("=================sb:" + sb);
// return sb;
// }
//
// @Override
// public String getServletPath() {
// System.out.println("==============getServletPath:" + super.getServletPath());
// return super.getServletPath();
// }
//
// };
// //
// ctx.setRequest(httpServletRequestWrapper);
// ctx.remove("routeHost");
// ctx.put(FilterConstants.SERVICE_ID_KEY, "mobile3");
// return null;
}
// 属于CAS单点登陆
// 通过截取地址栏,获得应该跳转的服务地址
String remove = StringUtils.remove(requestURI, "/cas/");
String targetJumpServiceId = StringUtils.substringBefore(remove, "/");
log.debug("截取到应该跳转的服务项目名为" + targetJumpServiceId);
ctx.remove("routeHost");
ctx.put(FilterConstants.SERVICE_ID_KEY, targetJumpServiceId);
}
}
return null;
}
/**
* 获得指定Cookie的值
*
* @param name
* 名称
* @return 值
*/
public static String getCookie(HttpServletRequest request, String name) {
String userName = getCookie(request, null, name, false);
if (StringUtils.isBlank(userName)) {
return null;
} else {
int index = userName.indexOf("@@");
if (index == -1) {
return userName;
} else {
return userName.substring(0, index);
}
}
}
/**
* 获得指定Cookie的值
*
* @param request
* 请求对象
* @param response
* 响应对象
* @param name
* 名字
* @param isRemove
* 是否移除
* @return 值
*/
public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name,
boolean isRemove) {
String value = null;
Cookie[] cookies = request.getCookies();
log.debug("get cookies is" + ArrayUtils.toString(cookies));
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(name)) {
try {
value = URLDecoder.decode(cookie.getValue(), StandardCharsets.UTF_8.name());
// break;
} catch (Exception e) {
log.error("cookie解码失败:" + cookie.getValue());
e.printStackTrace();
}
if (isRemove) {
cookie.setMaxAge(0);
// if
// (StringUtils.isNotBlank(SpringContextHolder.getApplicationContext().getApplicationName()))
// {
// cookie.setPath(SpringContextHolder.getApplicationContext().getApplicationName());
// } else {
// cookie.setPath("/");
// }
cookie.setPath("/");
log.debug("开始设置COOKIE:name is " + name + " value is " + value + " setMaxAge is 0");
response.addCookie(cookie);
}
}
}
}
return value;
}
public static void setCookie(HttpServletResponse response, String name, String value, int maxAge) {
Cookie cookie = new Cookie(name, null);
// if
// (StringUtils.isNotBlank(SpringContextHolder.getApplicationContext().getApplicationName()))
// {
// cookie.setPath(SpringContextHolder.getApplicationContext().getApplicationName());
// } else {
// cookie.setPath("/");
// }
cookie.setPath("/");
cookie.setMaxAge(maxAge);
try {
if (StringUtils.isNotEmpty(value)) {
cookie.setValue(URLEncoder.encode(value, "utf-8"));
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
log.debug("开始设置COOKIE:name is " + name + " value is " + value);
response.addCookie(cookie);
}
}
package com.leedarson;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@SpringBootApplication
public class LdszuulApplication {
public static void main(String[] args) {
SpringApplication.run(LdszuulApplication.class, args);
}
}
spring:
application:
name: ldszuul
server:
port: 1115
eureka:
instance:
prefer-ip-address: true
# lease-renewal-interval-in-seconds: 5
# lease-expiration-duration-in-seconds: 10
client:
serviceUrl:
defaultZone: http://test:test@127.0.0.1:1110/eureka/
# registry-fetch-interval-seconds: 5
zuul:
sensitive-headers: null
ignored-services: eureka,ldstrubine,configserver
host:
connect-timeout-millis: 4000
connection-request-timeout-millis: 2000
ribbon:
eager-load:
enabled: true
ConnectTimeout: 3000
ReadTimeout: 10000
SocketTimeout: 1000
management:
endpoints:
web:
exposure:
include: routes,filters,details
endpoint:
shutdown:
enabled: false
logging:
level:
root: INFO
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- 禁止缩放 -->
<meta name="viewport"
content="width=device-width,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, minimal-ui, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="format-detection" content="telephone=no">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html {
height: 100%
}
body {
height: 100%;
margin: 0px;
padding: 0px
}
</style>
</head>
<body>
z404
<script type="text/javascript">
</script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- 禁止缩放 -->
<meta name="viewport"
content="width=device-width,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, minimal-ui, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="format-detection" content="telephone=no">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html {
height: 100%
}
body {
height: 100%;
margin: 0px;
padding: 0px
}
</style>
</head>
<body>
z500
<script type="text/javascript">
</script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- 禁止缩放 -->
<meta name="viewport"
content="width=device-width,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, minimal-ui, user-scalable=no">
<!-- 默认删除苹果的菜单栏和地址栏 -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!-- 禁止苹果把一串数字自动识别手机号码 -->
<meta name="format-detection" content="telephone=no">
<!-- 清除缓存,能让qq浏览器和safari在回退操作后仍然运行js -->
<!-- 最大的缺点就是 会重新载入页面的js和css文件,严重影响载入速度,最好的方式就是采取单页模式
<meta HTTP-EQUIV="pragma" CONTENT="no-cache">
<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate,no-siteapp">
-->
<title></title>
<!-- <link rel="stylesheet" href="#"> -->
<style type="text/css">
/*
*box-sizing属性可以为三个值之一:content-box(default),border-box,padding-box。
*content-box,border和padding不计算入width之内
*padding-box,padding计算入width内
*border-box,border和padding计算入width之内
*如果不设置box-sizing,则请使用 calc() 避免。exp:
*写给不支持calc()的浏览器
* width:-moz-calc(100% - (10px + 5px) * 2);
* width:-webkit-calc(100% - (10px + 5px) * 2);
* width: calc(100% - (10px + 5px) * 2);
*/
* {
margin: 0;
padding: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html {
height: 100%
}
body {
height: 100%;
margin: 0px;
padding: 0px
}
</style>
</head>
<body>
T222222222222222222222222222222222222222222222
<script type="text/javascript">
</script>
</body>
</html>
\ No newline at end of file
package com.leedarson;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class LdszuulApplicationTests {
@Test
public void contextLoads() {
}
}
......@@ -3,8 +3,8 @@ spring:
name: eureka
security:
user:
name: sinra
password: mobiledev
name: test
password: test
server:
port: 1110
eureka:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment