点击上方“全栈程序员社区”,星标公众号
作者:Hpsyche
blog.csdn.net/Hpsyche/article/details/102926010
前言
在微服务体系架构中,网关承担着重要的角色,在网关中可以添加各种过滤器,过滤请求,保证请求参数安全,限流等等。如果请求绕过了网关,那就等于绕过了重重关卡,直捣黄龙,所以,在分布式架构中,我们需要有一定的防范,来确保各个服务相互之间安全调用。
正文
思路
1、在网关中给所有请求加上一个请求密钥
2、在服务添加过滤器,验证密钥
首先在网关服务(gateway)中添加过滤器,给放行的请求头上加上判断
package com.hpsyche.hpsychegatewayserver.filter;
import com.hpsyche.hpsychegatewayserver.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @author Hpsyche
*/
public class TokenFilter implements GlobalFilter {
@Autowired
private RedisUtil redisUtil;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//token(用户身份)判断
................
ServerHttpRequest req = exchange.getRequest().mutate()
.header("from", "gateway").build();
return chain.filter(exchange.mutate().request(req.mutate().build()).build());
}
}
如果考虑到安全性的话,这里header的值也可以使用UUID,并保存至redis中,在其他服务中通过redis读取判断身份。
在主服务,如auth授权服务上,添加全局拦截器,判断header上是否有对应的value,是则否则,反之拦截。
package com.hpsyche.hpsycheauthserver.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* @author Hpsyche
*/
@Slf4j
public class GlobalInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception {
String secretKey = request.getHeader("from");
if(!StringUtils.isNotBlank(secretKey)||secretKey.equals("gateway"){
response.setContentType("application/json; charset=utf-8");
PrintWriter writer = response.getWriter();
writer.write("error");
return false;
}
return true;
}
}
此时,绕过网关,直接访问auth服务的接口会返回error,即必须通过网关,我们的任务看似完成了。
问题
在项目中,发现了feign远程调用会失败,因为在fegin中调用不通过gateway,缺少from的请求头,会被拦截器拦截,导致调用失败。
解决方案
在auth-client(服务暴露方)添加请求头,在供其他服务调用时添加header。
package com.hpsyche.hpsycheauthclient.config;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;
/**
* Feign调用的时候添加请求头from
*/
@Configuration
public class FeignConfiguration implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {;
requestTemplate.header("from", "gateway");
}
}
同时,需要在service接口中添加configuration配置:
package com.hpsyche.hpsycheauthclient.api;
import com.hpsyche.hpsychecommonscommon.vo.BaseResponse;
import com.hpsyche.hpsycheauthclient.config.FeignConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author Hpsyche
*/
@FeignClient(value = "hpsyche-auth-server",configuration = FeignConfiguration.class)
public interface AuthService {
@PostMapping("/auth/verifyUser")
BaseResponse verifyUser(@RequestParam("username")String username,@RequestParam("password") String password);
}
由此,实现了feign调用时请求头的追加。
总结
遇到问题多思考,多学习;在搭建服务时自己也遇到了不少问题,通过搜索、借鉴其他大佬们的博客经验才得以解决。由于博主水平有限,如有不足之处望指出!
原文始发于微信公众号(全栈程序员社区):SpringCloud确保服务只能通过gateway转发访问,禁止直接调用接口访问
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/102150.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...