如何在Tomcat中拦截出站登录请求并判断其来源?
当然有办法啦!得先明确你说的「出站登录请求」具体是哪种场景——是你的Tomcat应用作为客户端,主动向外部服务发起的登录请求?还是你其实想判断发起登录请求的客户端是内网还是外网,然后在Tomcat发送响应前做拦截?我把两种常见场景的方案都梳理清楚,你按需选用:
场景1:拦截Tomcat作为客户端发起的出站HTTP登录请求
如果你的应用代码里用RestTemplate、Apache HttpClient这类工具调用外部认证服务的登录接口,想要拦截这类出站请求并判断目标地址是内网还是外网,可以用HTTP客户端自带的拦截器实现:
以Spring RestTemplate为例
自定义一个ClientHttpRequestInterceptor,在拦截器里获取目标地址并判断:public class OutboundLoginInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { // 获取请求的目标URI URI targetUri = request.getURI(); String host = targetUri.getHost(); // 判断目标地址是内网还是外网(逻辑可根据实际情况调整) boolean isInternal = isInternalHost(host); // 执行你的业务逻辑,比如日志记录、权限校验等 if (isInternal) { System.out.println("出站登录请求目标为内网地址:" + host); } else { System.out.println("出站登录请求目标为互联网地址:" + host); } // 继续执行请求 return execution.execute(request, body); } private boolean isInternalHost(String host) { try { InetAddress address = InetAddress.getByName(host); // 利用JDK自带方法判断是否为内网地址 return address.isSiteLocalAddress(); } catch (UnknownHostException e) { // 如果解析IP失败,可根据域名后缀判断(比如.intranet、.local) return host != null && host.endsWith(".intranet"); } } }之后把这个拦截器注册到RestTemplate:
RestTemplate restTemplate = new RestTemplate(); restTemplate.getInterceptors().add(new OutboundLoginInterceptor());要是用Apache HttpClient,自定义
HttpRequestInterceptor的逻辑是类似的,核心都是在请求发送前获取目标主机信息做判断。
场景2:拦截登录请求的出站响应(判断客户端来源)
如果你实际需求是判断向Tomcat发起登录请求的客户端是内网还是外网,然后在发送响应前做拦截处理,有两种常用方案:
Tomcat Valve(全局底层拦截)
自定义Valve继承ValveBase,可以在Tomcat层面全局拦截所有请求:public class LoginSourceValve extends ValveBase { @Override public void invoke(Request request, Response response) throws IOException, ServletException { // 只拦截登录接口,比如匹配你的登录URL String requestUri = request.getRequestURI(); if ("/your-login-path".equals(requestUri)) { // 获取客户端IP地址 String clientIp = request.getRemoteAddr(); // 判断客户端是否来自内网 boolean isInternal = isInternalIp(clientIp); // 执行你的逻辑,比如记录日志、限制内网/外网登录权限等 if (isInternal) { System.out.println("登录请求来自内网IP:" + clientIp); } else { System.out.println("登录请求来自互联网IP:" + clientIp); } } // 传递请求给下一个Valve getNext().invoke(request, response); } private boolean isInternalIp(String ip) { // 内网IP段判断逻辑,覆盖常见的私有IP范围 String[] ipParts = ip.split("\\."); if (ipParts.length != 4) return false; int firstOctet = Integer.parseInt(ipParts[0]); int secondOctet = Integer.parseInt(ipParts[1]); return firstOctet == 10 || (firstOctet == 172 && secondOctet >= 16 && secondOctet <= 31) || (firstOctet == 192 && secondOctet == 168); } }然后在Tomcat的
server.xml里配置这个Valve,放在Engine或Host标签下即可生效:<Engine name="Catalina" defaultHost="localhost"> <Valve className="com.your.package.LoginSourceValve" /> <!-- 其他原有配置 --> </Engine>Servlet Filter(应用级拦截)
如果你只想在当前Web应用内拦截登录请求,用Servlet Filter更轻便:@WebFilter(urlPatterns = "/your-login-path") public class LoginSourceFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; String clientIp = httpRequest.getRemoteAddr(); boolean isInternal = isInternalIp(clientIp); // 这里添加你的业务逻辑 // 继续执行后续过滤链 chain.doFilter(request, response); } private boolean isInternalIp(String ip) { // 同上面的内网IP判断逻辑 String[] ipParts = ip.split("\\."); if (ipParts.length != 4) return false; int firstOctet = Integer.parseInt(ipParts[0]); int secondOctet = Integer.parseInt(ipParts[1]); return firstOctet == 10 || (firstOctet == 172 && secondOctet >= 16 && secondOctet <= 31) || (firstOctet == 192 && secondOctet == 168); } }
内容的提问来源于stack exchange,提问作者zackhalil
相关产品推荐
相关产品推荐

