环境描述:
一个注册中心,一个 springCloud API网关 zuul,一个用户系统,一个账户系统。
http://localhost:5555/account 访问的是账号系统
http://localhost:5555/user 访问的是用户系统
问题现象:
在没登录的情况下访问 http://localhost:5555/account/walletTopUp?amount=40 正常应该跳转到 http://localhost:5555/user/login ,但跳转到 http://localhost:5555/account/login
zuul 过滤器代码
package com.sande.apigateway.security;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.sande.apigateway.utilsInterface.ITokenManagement;
import java.io.IOException;
import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class LoginFilter extends ZuulFilter {
private static Logger logger = LoggerFactory.getLogger(LoginFilter.class);
private String[] excludeUrls;
@Resource ITokenManagement iTokenManagement;
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletResponse response =ctx.getResponse();
try {
//不过滤的uri
String[] notFilter = new String[]{"/user/login","/user/userLogin","/user/js"};
//请求的uri
String uri = request.getRequestURI();
System.out.println("filter>>>uri>>>"+uri);
//是否过滤
boolean doFilter = true;
for(String s : notFilter){
if(uri.indexOf(s) != -1){
//uri中包含不过滤uri,则不进行过滤
doFilter = false;
//fc.doFilter(request, response);
ctx.setSendZuulResponse(true); //将请求往后转发
ctx.setResponseStatusCode(200);
break;
}
}
if(doFilter){
//去cookie里面拿
String token ="";
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
String cookieName = cookie.getName();
String cookieValue = cookie.getValue();
token = cookieValue;
//System.out.println(cookieName + ", " + cookieValue);
}
if (iTokenManagement.validationToken(token)) {
//fc.doFilter(request, response);
ctx.setSendZuulResponse(true); //将请求往后转发
ctx.setResponseStatusCode(200);
//System.out.println("Token: " + token);
} else {
response.sendRedirect("./login");
}
}
} catch (NullPointerException e) {
try {
response.sendRedirect("./login");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} catch (Exception e) {
logger.error("登录过滤验证异常");
/*ctx.set("error.status_code",HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
ctx.set("error.exception",e);*/
e.printStackTrace();
}
return null;
}
}
过滤器的逻辑是,访问用户系统 "/user/login","/user/userLogin" 接口及JS页面的请求直接放行,其他请求则要检查是否有Token(如果之前成功登陆了就会有 Token),没有 Token 就跳到用户系统的登录页面。
zuul 参数配置:
spring.application.name=api-gateway
server.port = 5555
eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka/
zuul.routes.user-service.path=/user/**
zuul.routes.user-service.serviceId=user-server
zuul.routes.account-server.path=/account/**
zuul.routes.account-server.serviceId=account-server
zuul.routes.user-service.strip-prefix=false
zuul.routes.account-server.strip-prefix=false
zuul.routes.user-service.custom-sensitive-headers=true
zuul.routes.account-server.custom-sensitive-headers=true
zuul.add-host-header=true
#zuul.routes.api.url=http://user-server/user/**
#zuul.routes.user.path=/user/**
#zuul.routes.user.url=http://localhost:8080/user
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.timeout=10000
spring.redis.database=0
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
解决办法:修改 zuul 过滤器,把跳转路径有 ./login 改为 /user/login
package com.sande.apigateway.security;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.sande.apigateway.utilsInterface.ITokenManagement;
import java.io.IOException;
import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class LoginFilter extends ZuulFilter {
private static Logger logger = LoggerFactory.getLogger(LoginFilter.class);
private String[] excludeUrls;
@Resource ITokenManagement iTokenManagement;
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletResponse response =ctx.getResponse();
try {
//不过滤的uri
String[] notFilter = new String[]{"/user/login","/user/userLogin","/user/js"};
//请求的uri
String uri = request.getRequestURI();
System.out.println("filter>>>uri>>>"+uri);
//是否过滤
boolean doFilter = true;
for(String s : notFilter){
if(uri.indexOf(s) != -1){
//uri中包含不过滤uri,则不进行过滤
doFilter = false;
//fc.doFilter(request, response);
ctx.setSendZuulResponse(true); //将请求往后转发
ctx.setResponseStatusCode(200);
break;
}
}
if(doFilter){
//去cookie里面拿
String token ="";
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
String cookieName = cookie.getName();
String cookieValue = cookie.getValue();
token = cookieValue;
//System.out.println(cookieName + ", " + cookieValue);
}
if (iTokenManagement.validationToken(token)) {
//fc.doFilter(request, response);
ctx.setSendZuulResponse(true); //将请求往后转发
ctx.setResponseStatusCode(200);
//System.out.println("Token: " + token);
} else {
response.sendRedirect("/user/login");
}
}
} catch (NullPointerException e) {
try {
response.sendRedirect("/user/login");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} catch (Exception e) {
logger.error("登录过滤验证异常");
/*ctx.set("error.status_code",HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
ctx.set("error.exception",e);*/
e.printStackTrace();
}
return null;
}
}