微服务调用安全有两个方面
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请求
结果 (被调用方拦截)