一:zuul动态路由分发,zuul可以访问其他资源的原理
1.1 zuul访问其他资源原理:
1.1.1 zuul由一堆过滤器zuulfilter组成过滤器链实现:过滤器的类型有 pre rout post error
定义一个过滤器:继承ZuulFilter
@Component
public class MySendResponseFilter extends ZuulFilter {
@Override
public String filterType() {return PRE_TYPE; }//定义过滤器类型
@Override
public int filterOrder() { return FORM_BODY_WRAPPER_FILTER_ORDER+1; }//定义当前过滤顺序,相同类型的过滤器数字越小越先执行
@Override
public boolean shouldFilter(){return true;}//当前过滤器是否应该执行
@Override
public Object run() throws ZuulException { return null; }//当前过滤器实现逻辑的地方
}
1.1.2 过滤器的执行顺序是:pre->rout->资源服务器->post/error
1.1.3 rout 类型的过滤器默认有四个:
RibbonRoutingFilter order:10 请求资源服务前的最后一个路由
SimpleRoutingFilter order:100 请求资源服务后的第一个路由
SendForwardFilter order:200
SendResponseFilter order:1000
过滤器访问服务器的关键过滤器是rout类型的RibbonRoutingFilter
//这是RibbonRoutingFilter的shouldFilter()方法。
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return (ctx.getRouteHost() == null && ctx.get(SERVICE_ID_KEY) != null
&& ctx.sendZuulResponse());
}
//ctx.sendZuulResponse()默认为true,所以在自定义的pre类型过滤器中如果不想请求资源服务可以设置ctx .setSendZuulResponse(false);
1.2 动态路由分发:
1.2.1 一个请求过来:localhost:9999/auth/hello/1
zuul是如何正确将当前请求转发到对应的资源服务器:auth-service 并且访问路径路径为/hello/1
理解了这个问题就理解了zuul动态路由分发
1.2.2 首先我们应该配置ZuulProperties .ZuulRoute 告诉zuul如果请求中包含路径/auth/**,
就上面提到的调用RibbonRoutingFilter请求auth-service这个服务。
1.2.3 所以我们需要 用到zuul提供的关键类:DiscoveryClientRouteLocator的两个关建方法:
refresh()和locateRoutes()
public class MyDiscoverClientRouterLocator extends DiscoveryClientRouteLocator {
/**
* 根据心跳时间动态刷新路由配置(间隔调用locateRoutes()方法)
* 设置方法配置文件设置30s刷新一次:registry-fetch-interval-seconds: 30
*/
@Override
public void refresh() {
super.refresh();
}
/**
* 自定义zuulRoute,可以设置为从db中获取
* @return
*/
@Override
protected LinkedHashMap<String, ZuulProperties.ZuulRoute> locateRoutes() {
return super.locateRoutes();
}
public MyDiscoverClientRouterLocator(String servletPath, DiscoveryClient discovery, ZuulProperties properties, ServiceInstance localServiceInstance) {
super(servletPath, discovery, properties, localServiceInstance);
}
}
@Configuration
public class DynamicRouteConfiguration {
private Registration registration;
private DiscoveryClient discovery;
private ZuulProperties zuulProperties;
private ServerProperties server;
private RedisTemplate redisTemplate;
public DynamicRouteConfiguration(Registration registration, DiscoveryClient discovery,
ZuulProperties zuulProperties, ServerProperties server, RedisTemplate redisTemplate) {
this.registration = registration;
this.discovery = discovery;
this.zuulProperties = zuulProperties;
this.server = server;
this.redisTemplate = redisTemplate;
}
@Bean
public DynamicRouteLocator dynamicRouteLocator() {
return new DynamicRouteLocator(server.getServletPrefix()
, discovery
, zuulProperties
, registration
, redisTemplate);
}
}
二:网关统一异常拦截:理解了一,异常拦截就简单,创建一个类型为error类型的过滤器。
@Override
public boolean shouldFilter() {
RequestContext requestContext = RequestContext.getCurrentContext();
return requestContext.getThrowable() != null;
}
@Override
public Object run() {
RequestContext requestContext = RequestContext.getCurrentContext();
logSendService.send(requestContext);
return null;
}
三:认证授权
zuul: pre类型的默认最后两个过滤器分别是
AuthenticationHeaderFilter order=9
Oauth2TokenRelayFilter order=10
1.1 认证过程其实就是获取jwt token的过程,oauth2提供了给我们返回token的方法,不用自己写。
我们获取token有四种方式:
1,授权码模式
2,简化模式
3,密码模式
4,客户端模式
阮大神这篇文章写的很好:https://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html;参考
1.2 oauth2给我们提供默认controller类TokenEndpoint来获取token
@RequestMapping(value = "/oauth/token", method=RequestMethod.GET)
public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal, @RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
if (!allowedRequestMethods.contains(HttpMethod.GET)) {
throw new HttpRequestMethodNotSupportedException("GET");
}
return postAccessToken(principal, parameters);
}