微服务调用安全有两个方面
1.客户端调用微服务的安全问题,通过zuul的网关去解决。当是我们想在ueurka内建一个小团体,所以请求头加了token(相当于多加了一道锁子)
2.微服务之间的调用的安全问题,通过fegin调用,解决思路是在调用时请求头加上token,让被调用方验证token的有效性
所以以上两种安全可以用同一种思路去解决,简化流程,提高安全
一、被调用方的过滤器的解决
在启动类中添加
@Bean public FilterRegistrationBean testFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(new LoginFilter()); List<String> urlPatterns = new ArrayList<String>(); urlPatterns.add("/*"); registration.setUrlPatterns(urlPatterns); registration.setEnabled(true); //过滤器的开关 return registration; }
过滤类
import org.springframework.web.context.support.SpringBeanAutowiringSupport; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class LoginFilter implements Filter { protected static List<Pattern> patterns = new ArrayList<Pattern>(); @Override public void init(FilterConfig filterConfig) throws ServletException { SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, filterConfig.getServletContext()); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; String usertoken = httpRequest.getHeader("usertoken"); String url = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length()); String[] regex=new String[10] ; regex[0]="^login.*$"; /** * swagger的url */ regex[1]="^v2.*$"; regex[2]="^webjars.*$"; regex[3]="^swagger.*$"; for (int i=0;i<=3;i++) { patterns.add(Pattern.compile(regex[i])); } if (url.startsWith("/") && url.length() > 1) { url = url.substring(1); } if (isInclude(url)){ filterChain.doFilter(httpRequest, httpResponse); return; }else { //过滤条件的判断和业务处理 } } @Override public void destroy() { } private boolean isInclude(String url) { for (Pattern pattern : patterns) { Matcher matcher = pattern.matcher(url); if (matcher.matches()) { return true; } } return false; } }
二、在调用方通过fegin访问
接口类
import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMapping; @Component @FeignClient(value = "bbb") public interface ServiceClient { @RequestMapping("/xxx/selectone") String printf(); }
controller类
@RestController public class ConsumerController { @Autowired private ServiceClient serviceClient; @RequestMapping("/test") public String test(){ //可以在此处获得请求头信息 return serviceClient.printf(); } }
三、核心配置
调用方的fegin配置类
@Configuration public class FeignConfiguration { /** * 日志级别 * @return */ @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } /** * 创建Feign请求拦截器,在发送请求前设置认证的token,各个微服务将token设置到环境变量中来达到通用 * @return */ @Bean public FeignBasicAuthRequestInterceptor basicAuthRequestInterceptor() { return new FeignBasicAuthRequestInterceptor(); } }
调用方的请求拦截类
import feign.RequestInterceptor; import feign.RequestTemplate; /** * Feign请求拦截器 * @author yinjihuan * @create 2017-11-10 17:25 **/ public class FeignBasicAuthRequestInterceptor implements RequestInterceptor { public FeignBasicAuthRequestInterceptor() { } @Override public void apply(RequestTemplate template) { System.setProperty("auth.token","abc"); //这个可以通过其他类来设置到全局变量中 template.header("usertoken", System.getProperty("auth.token")); } }
推荐在调用方的过滤器中将 auth.token set到全局变量中
或者在调用方的controller中,先获取请求头信息在发送fegin请求
结果 (被调用方拦截)