使用zuul实现验证自定义请求头中的token
路由:她会把外部所有对请求转发到具体的微服务实例上,是实现外部访问同一接口的基础
过滤: 就是权限的检查, 判断当前的请求是否有权限区访问那些服务集群
搭建后台网关:
-
导入eureka – client, 它本身也是一个客户端,需要注册进eureka
- 导入网关的包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
过滤器, 重写下面的ZuulFilter可以实现自定义的过滤规则, 每个方法的含义都通过注释的方式写在了方法头
网关的过滤器
@Component
public class WebManagerFilter extends ZuulFilter {
/**
* 指定过滤器的类型
pre :可以在请求被路由之前调用
route :在路由请求时候被调用
post :在route和error过滤器之后被调用
error :处理请求时发生错误时被调用
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 指定过滤器的优先级, 0表示优先执行, 因为我们可以写很多个过滤器
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 当前过滤器是否开启, true表示开启
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器执行逻辑, 返回任意Object类型的值,都表示放行,包括null
* 如果不想往后继续执行了,就使用 setSendZullResponse(false)
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
System.out.println("经过了后台的过滤器");
return null;
}
}
我们可以通过RequestContext的实例对象,获取出请求头,请求parms,请求ip等信息, 针对不同的信息可以做出不同的处理
黑白名单
比如我们可以在网关中禁用掉恶意访问的ip地址
验证权限
如果项目是前后端分离使用jwt等工具生成token放在请求头中做安全验证,我们也能在网关中对请求头做出初步解析处理
防止抓包
还能根据用户请求中发送过来的请求参数做验证签名处理, 防止数据在传输过程中被恶意篡改
此外,网关会过滤掉一些请求的请求头,如果请求头是我们自己定义的,就比如下面的Authrization, 经过网关后的请求的头信息会丢失,进而导致下面的这段代码失效, 获取不出头信息,就没办法验证token的合法性
解决办法: 选着添加添加一条配置信息 sensitive-headers:
将这个配置置空,意为清空网关要过滤的请求头
RequestContext currentContext = RequestContext.getCurrentContext();
String header = currentContext .getRequest().getHeader("Authorization");
System.err.println("zull header "+header);
// 判断是否存在header
if (!"".equals(header)&&header!=null){
System.err.println("转发header");
currentContext.addZuulRequestHeader("Authorization",header);
}
使用过滤器做验证的逻辑如下,验证携带在请求头中的token信息如下:
这个方法的特点就是, 只要他能在遇到 return null
就表示成功完成了验证的逻辑
1. 导入 common,我们要使用它的jwtUtil
@Override
public Object run() throws ZuulException {
System.err.println("经过了后台的过滤器");
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
// 获取出请求头
String header = request.getHeader("Authorization");
// 放行zuul的第一次请求 todo 我并没有触发这个方法的执行
if (request.getMethod().equals("OPTIONS")){
System.err.println("OPTIONS");
return null;
}
// 放行登录请求
if (request.getRequestURL().indexOf("login")>0){
return null;
}
if (StringUtils.isNotBlank(header)){
if (header.startsWith("Bearer ")){
String token = header.substring(7);
if (StringUtils.isNotBlank(token)){
System.out.println("token=="+token);
try{
Claims claims = jwtUtil.parseJWT(token);
String roles =(String) claims.get("roles");
System.out.println("roles=="+roles);
// 对admin放行,
if (roles.equals("admin")){
return null;
}
// todo 转发头信息,我改了配置文件, 让zuul不过滤任何头信息
// 其他情况, 终止访问
currentContext.setSendZuulResponse(false);
}catch (Exception e){
// 解析token出现的异常,说明token有问题, 终止本次请求
System.out.println("token出错了,终止本次访问: "+e);
currentContext.setSendZuulResponse(false);
}
}
}
}
currentContext.setSendZuulResponse(false);
currentContext.getResponse().setContentType("text/html;chatset=utf-8");
try {
currentContext.getResponse().getWriter().write("权限不足");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}