一篇理解zuul整合Security实现实现动态路由分发,统一异常拦截,认证授权

一: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);
	}

你可能感兴趣的:(springCloud)