导读
由于项目需要,这里需要设计一个IP白名单,增加接口安全。SpringBoot项目,因为接口已经开发好,在不变动接口的情况下,采用拦截器做处理,思路是拦截指定的请求,获取到该请求的IP,然后根据该ip去数据库查询是否存在,如果存在就允许访问,否则没有权限访问。(PS:拦截器可以通过访问Service层,在service层添加Redis缓存,设置下缓存失效时间,这样就不需要每次访问接口就从数据库中查一遍,减轻数据库访问压力,点击查看Redis缓存配置,目前这里未设置Redis缓存)
使用
创建表ip_filter
CREATE TABLE `ip_filter` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '序号',`ip` varchar(255) NOT NULL COMMENT 'ip地址',`whitelists` tinyint(4) NOT NULL COMMENT '白名单0:黑名单1',`module` varchar(255) DEFAULT NULL COMMENT '模块',`create_time` datetime DEFAULT NULL COMMENT '创建时间',`modify_time` datetime DEFAULT NULL COMMENT '修改时间',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='IP白名单表';
创建实体类和Mapper查询接口
- 实体类IpFilter ```java
/**
ip过滤器实体类 */ @Data public class IpFilter implements Serializable {
private static final long serialVersionUID = 8802493743077425037L; /**
ip地址 */ private String ip;
/**
白名单—0,黑名单—1 */ private Integer whitelists;
/**
模块 */ private String module;
/**
创建时间 */ private Date createTime;
/**
- 修改时间 */ private Date modifyTime; }
- **Mapper接口IpFilterMapper**```javaimport com.demo.common.entity.IpFilter;import org.apache.ibatis.annotations.*;import org.springframework.stereotype.Component;import java.util.List;@Mapper@Componentpublic interface IpFilterMapper {/*** 从数据库中查询IP是否存在** @param ipFilter* @return*/@Select("select * from ip_filter where ip = #{query.ip} and whitelists=#{query.whitelists}")@Results(id = "ipFilterMessage",value = {@Result(column = "ip", property = "ip"),@Result(column = "module", property = "module"),@Result(column = "whitelists", property = "whitelists"),@Result(column = "create_time", property = "createTime"),@Result(column = "modifyTime", property = "modify_time")})List<IpFilter> selectIpFilterByRealIp(@Param("query") IpFilter ipFilter);}
获取工具类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才是真实ipif (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.IpFilter;import com.demo.common.mapper.IpFilterMapper;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 拦截器*/@Componentpublic class IPInterceptor implements HandlerInterceptor {private static Logger LOG = LoggerFactory.getLogger(IPInterceptor.class);@Autowiredprivate IpFilterMapper ipFilterMapper;@Overridepublic 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)) {return false;}IpFilter ipFilter = new IpFilter();//可以访问模块ipFilter.setModule("test");//ip地址ipFilter.setIp(ipAddress);//白名单ipFilter.setWhitelists(0);List<IpFilter> ips = ipFilterMapper.selectIpFilterByRealIp(ipFilter);if (ips.isEmpty()) {response.getWriter().append("<h1 style=\"text-align:center;\">Not allowed!</h1>");return false;}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic 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;@Configurationpublic class GlobalCorsConfig extends WebMvcConfigurerAdapter {@Autowiredprivate IPInterceptor ipInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 添加拦截器,配置拦截地址,这里拦截以api请求的接口比如http://localhost/api/getUserregistry.addInterceptor(ipInterceptor).addPathPatterns("/api/**");}/**//跨域请求拦截器@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowCredentials(true).allowedHeaders("*").allowedOrigins("*").allowedMethods("*");}*/}
END
这里还没有做限流处理,下次考虑试下限流。
