导读
由于项目需要,这里需要设计一个IP白名单,增加接口安全。SpringBoot项目,因为接口已经开发好,在不变动接口的情况下,采用拦截器做处理,思路是拦截指定的请求,获取到该请求的IP,然后根据该ip去配置文件查询是否存在,如果存在就允许访问,否则没有权限访问。
使用
创建配置文件ip_address.yml
address:
ipFilters:
- ip: 127.0.0.1
whitelists: true
- ip: 192.168.255.255
whitelists: true
创建读取配置YML文件属性PropConfig
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import java.util.Objects;
/**
* 读取配置文件
*/
@Configuration
public class PropConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("ip_address.yml"));
configurer.setProperties(Objects.requireNonNull(yaml.getObject()));
return configurer;
}
}
创建实体类和IPAddress类
- 实体类IpFilter ```java import java.io.Serializable;
/**
ip过滤器实体类 */ public class IpFilter implements Serializable {
private static final long serialVersionUID = 8802493743077425037L; /**
ip地址 */ private String ip;
/**
白名单—true,黑名单—false */ private Boolean whitelists;
public String getIp() { return ip; }
public void setIp(String ip) { this.ip = ip; }
public Boolean getWhitelists() { return whitelists; }
public void setWhitelists(Boolean whitelists) { this.whitelists = whitelists; } }
- **IpAddress类**
```java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.io.Serializable;
import java.util.List;
/**
* IpAddress 存放集合属性
*/
@Configuration
@ConfigurationProperties("address")
@Data
public class IpAddress implements Serializable {
private static final long serialVersionUID = -1686798098991604714L;
private List<IpFilter> ipFilters; //ipFilters与yml文件的集合属性对应
}
获取工具类IPUtils
import javax.servlet.http.HttpServletRequest;
/**
* 获取用户的IP
*/
public class IPUtils {
/**
* 本地IP localhost
*/
private static final String NATIVEIP = "0:0:0:0:0:0:0:1";
/**
* 获取用户真实IP地址,不使用request.getRemoteAddr()的原因是有可能用户使用了代理软件方式避免真实IP地址,
* 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值
*
* @return ip
*/
public static String getRealIP(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个ip值,第一个ip才是真实ip
if (ip.indexOf(",") != -1) {
ip = ip.split(",")[0];
}
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
System.out.println("Proxy-Client-IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
System.out.println("WL-Proxy-Client-IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
System.out.println("HTTP_CLIENT_IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
System.out.println("HTTP_X_FORWARDED_FOR ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
System.out.println("X-Real-IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
System.out.println("getRemoteAddr ip: " + ip);
}
if (ip.equals(NATIVEIP)) {
ip = "127.0.0.1";
System.out.println("get native ip" + ip);
}
return ip;
}
}
拦截器IPInterceptor
import com.demo.common.entity.IpAddress;
import com.demo.common.entity.IpFilter;
import com.demo.common.utils.IPUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* IP 拦截器
*
* @author hyanchao
* @create 2020/1/14 14:23
*/
@Component
public class IPInterceptor implements HandlerInterceptor {
private static Logger LOG = LoggerFactory.getLogger(IPInterceptor.class);
@Autowired
private IpAddress address;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//过滤ip,若用户在白名单内,则放行
String ipAddress = IPUtils.getRealIP(request);
LOG.info("USER IP ADDRESS IS =>" + ipAddress);
if (!StringUtils.isNotBlank(ipAddress)) {
response.getWriter().append("<h1 style=\"text-align:center;\">Not allowed!</h1>");
return false;
}
//读取ip地址白名单集合,如果存在,并且为白名单,则放行,不然就拦截
List<IpFilter> ipFilters = address.getIpFilters();
if (ipFilters != null) {
for (IpFilter ips : ipFilters) {
if (ipAddress.equals(ips.getIp()) && ips.getWhitelists()) {
return true;
}
}
}
response.getWriter().append("<h1 style=\"text-align:center;\">Not allowed!</h1>");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
全局配置拦截
import com.demo.common.interceptor.IPInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class GlobalCorsConfig extends WebMvcConfigurerAdapter {
@Autowired
private IPInterceptor ipInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加拦截器,配置拦截地址,这里拦截以api请求的接口比如http://localhost/api/getUser
registry.addInterceptor(ipInterceptor).addPathPatterns("/api/**");
}
}
END
这里还没有做限流处理,下次考虑试下限流。