SpringCloud微服务学习----------Zuul的综合使用

假如我们现在有一个需求,权限的校验,要在所有的请求多一个tonken参数,

如果按着原来的做法是不是得每一个接口都要先校验一遍呢

http://192.168.66.63:30600/postman/eurekaApi/test?token=123

下面我用Zuul来实现校验所有请求必须加入一个token,并且值不为空,开始搞事情

首先在Zuul服务上建立一个类并继承ZuulFilter

这得实现四个方法,这时候我们需要用到一个常量类

Eclipse查询类的快捷是C+S+H

这个类貌似是专门提供校验规则的,来写写

package com.sola.filter;

import javax.servlet.http.HttpServletRequest;

import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
@Component
public class TokenFilter extends ZuulFilter{

	@Override
	public Object run() throws ZuulException {
		// 这里就是我们要处理的逻辑代码编写处了
		//这个是Zuul自己封装的 看清导入的包
		RequestContext currentContext = RequestContext.getCurrentContext();
	
		HttpServletRequest request = currentContext.getRequest();
		//再从参数里去拿token,也可以从Cookie和header里获取
		String token = request.getParameter("token");
		
		//判断token是否为空
		if(StringUtils.isEmpty(token)){
			//往Zuul设置没有权限
			currentContext.setSendZuulResponse(false);
			//再设置一个状态码,权限不足一般是401
			currentContext.setResponseStatusCode(401);
		}
		
		return true;
	}

	@Override
	public boolean shouldFilter() {
		// 个人理解这个应该是设置过滤器是否执行。。
		// 默认false 改成true
		return true;
	}

	@Override
	public int filterOrder() {
		//这个呢就是顺序,一种过滤器(前置)会都很多道过滤器
		//这个就是指定道放在哪个位置执行,数值越小的越靠前
		//暂时可以放到这个之前 那么我们可以 -1来实现
		return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
	}

	@Override
	public String filterType() {
		//下面实现参数校验,所以用这个常量
		//这人理解这个应该是指定过滤器的类型(之前讲过的前置,后置)
		//这里指的前置
		return FilterConstants.PRE_TYPE;
	}

}

之后我们去源地址访问一下,不加Token

加Token

————————————————————————————————————————————————————————

下面来写一个后置过滤器,再处理完的结果进行加工 

package com.sola.filter;

import javax.servlet.http.HttpServletResponse;

import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
@Component
public class BeforFilter extends ZuulFilter{

	@Override
	public Object run() throws ZuulException {
		// 搞事情
		RequestContext currentContext = RequestContext.getCurrentContext();
				
		HttpServletResponse response = currentContext.getResponse();
				
		response.setHeader("solaHeader", "213213213");
		
		return null;
	}

	@Override
	public boolean shouldFilter() {
		// 个人理解这个应该是设置过滤器是否执行。。
		// 默认false 改成true
		return true;
	}

	@Override
	public int filterOrder() {
	
		// 这个需要放在他之前,个人感觉不放他之前就发给前端了= =
		return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1;
	}

	@Override
	public String filterType() {
		//下面实现参数校验,所以用这个常量
		//这人理解这个应该是指定过滤器的类型(之前讲过的前置,后置)
		//这里指的后置
		return FilterConstants.POST_TYPE;
	}

}

加入了一个请求头

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

Zuul限流

为什么要限流呢,比如说有一个接口是发短信的,这时候就要限制客户访问量,防止造成短信轰炸

Zuul的前置过滤器有限流,又有鉴权

限流应该早于鉴权

下面介绍一种令牌桶限流

令牌桶这个算法 guava(谷歌开源的jar)已经实现了,我们直接拿来用就可以

先来加个依赖

		<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
			<dependency>
    			<groupId>com.google.guava</groupId>
    			<artifactId>guava</artifactId>
    			<version>26.0-jre</version>
			</dependency>

代码

package com.sola.filter;

import javax.servlet.http.HttpServletResponse;

import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.sola.exception.RateLimitException;

/**
 * @author JAVA
 *	限流
 */
@Component
public class RateFilter extends ZuulFilter{
	
	//这就是去调用的Guava实现的,参数是每秒放入多少个令牌
	private static final RateLimiter ratelimiter = RateLimiter.create(100);

	@Override
	public boolean shouldFilter() {
		
		return true;
	}

	@Override
	public Object run() throws ZuulException {
		//判断是否拿到令牌
		if(!ratelimiter.tryAcquire()){
			//这里我们可以定义一个异常
			throw new RateLimitException();
		}
		
		return null;
		
	}

	@Override
	public String filterType() {
		
		return FilterConstants.PRE_TYPE;
	}

	@Override
	public int filterOrder() {
		// 限流就要做到优先级最高 比最高还要高 最高是-3
		return FilterConstants.SERVLET_DETECTION_FILTER_ORDER - 1;
	}

}
package com.sola.exception;

public class RateLimitException extends RuntimeException{

}

理论上完成了

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

鉴权和添加用户服务

代码写一写

package com.sola.filter;

import javax.servlet.http.HttpServletRequest;

import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
/**
 * @author JAVA
 *	权限拦截 
 *	postman 只能访问postman
 *	roadwork 只能访问roadwork
 *  config server 都能访问
 */
@Component
public class AuthFilter extends ZuulFilter{

	@Override
	public Object run() throws ZuulException {
		
		RequestContext currentContext = RequestContext.getCurrentContext();
		
		HttpServletRequest request = currentContext.getRequest();
		//检查地址是否包含postman
		if(request.getRequestURI().contains("postman")){
			//获取rule值
			String parameter = request.getParameter("rule");
			//判断是否为空
			if(StringUtils.isEmpty(parameter) || parameter == null){
				//空就是设置没权限
				currentContext.setSendZuulResponse(false);
				currentContext.setResponseStatusCode(401);	
			}else{
				//判断 全权限是否是postman权限 没有就滚蛋
				if(!parameter.equals("postman")){
					currentContext.setSendZuulResponse(false);
					currentContext.setResponseStatusCode(401);	
				}
			}
		}
		
		if(request.getRequestURI().contains("roadwork")){
			//获取rule值
			String parameter = request.getParameter("rule");
			//判断是否为空
			if(StringUtils.isEmpty(parameter) || parameter == null){
				//空就是设置没权限
				currentContext.setSendZuulResponse(false);
				currentContext.setResponseStatusCode(401);	
			}else{
				//判断 全权限是否是postman权限 没有就滚蛋
				if(!parameter.equals("roadwork")){
					currentContext.setSendZuulResponse(false);
					currentContext.setResponseStatusCode(401);	
				}
			}
		}
	
		return null;
	}

	@Override
	public boolean shouldFilter() {
		return true;
	}

	@Override
	public int filterOrder() {
		return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
	}

	@Override
	public String filterType() {
		return FilterConstants.PRE_TYPE;
	}

}

这样写是好写了,但是相当不好维护,可以稍微改变一下结构,每一个需要的权限单独写一个filter,看起来就好多了

package com.sola.filter;

import javax.servlet.http.HttpServletRequest;

import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
/**
 * @author JAVA
 *	权限拦截 
 *	postman 只能访问postman
 */
@Component
public class AuthFilter extends ZuulFilter{

	@Override
	public Object run() throws ZuulException {
		
		RequestContext currentContext = RequestContext.getCurrentContext();
		
		HttpServletRequest request = currentContext.getRequest();
		
			//获取rule值
			String parameter = request.getParameter("rule");
			//判断是否为空
			if(StringUtils.isEmpty(parameter) || parameter == null){
				//空就是设置没权限
				currentContext.setSendZuulResponse(false);
				currentContext.setResponseStatusCode(401);	
			}else{
				//判断 全权限是否是postman权限 没有就滚蛋
				if(!parameter.equals("postman")){
					currentContext.setSendZuulResponse(false);
					currentContext.setResponseStatusCode(401);	
				}
		}
	
		return null;
	}

	@Override
	public boolean shouldFilter() {
		RequestContext currentContext = RequestContext.getCurrentContext();
		
		HttpServletRequest request = currentContext.getRequest();
		
		//检查地址是否包含postman
		if(request.getRequestURI().contains("postman")){
			//如果包含就去执行run 不包含就跳别的过滤器		
			return true;
		}
		
		return false;
	}

	@Override
	public int filterOrder() {
		return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
	}

	@Override
	public String filterType() {
		return FilterConstants.PRE_TYPE;
	}

}

package com.sola.config;

import java.util.ArrayList;
import java.util.Arrays;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * @author JAVA
 *	解决跨域
 */

@Configuration
public class CorsConfig {

	@Bean
	public CorsFilter corsFilter(){
		
		final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		
		final CorsConfiguration config = new CorsConfiguration();
		
		//配置是否支持cookie跨域
		config.setAllowCredentials(true);
		//配置原始域,也可以指定www.a.com等等
		config.setAllowedOrigins(Arrays.asList("*"));
		//设置允许的头
		config.setAllowedHeaders(Arrays.asList("*"));
		//设置方法(get,post等)
		config.setAllowedMethods(Arrays.asList("*"));
		//设置缓存时间,同时间内不再检查500秒
		config.setMaxAge(500l);
		
		
		//对哪些域名进行配置,设置为所有
		source.registerCorsConfiguration("/**", config);
		
		return new CorsFilter(source);
		
	}
}

猜你喜欢

转载自blog.csdn.net/jiulanhao/article/details/82783183