背景:
最近項目中遇到關於對部分請求設置ip白名單的功能需求,在這簡單梳理一下我的開發步驟與思路
實踐步驟:
思路: 關於實現ip白名單的過濾我大致會想到三種實現方式:
- 對相關需要過濾的控制類進行單獨設置 -------------- 代碼臃腫,不利於維護
- 利用相關攔截器進行統一實現 --------------相對好實現 -----------我就以這種方法做介紹
- 前后端分離,讓前端控制ip請求 --------------你要是和前端關系好的話可以試試
第一步:
把相關的環境准備好,我這邊已經有現成的項目,我就在現成的項目進行演示,對其中涉及到保密的東西我會注釋掉,僅限參考

大致的項目架構就是這樣,我主要在config包中進行相關攔截器的開發工作。
先准備相關的攔截器:
/** * @author : HUHY http://www.cnblogs.com/huhongy/ * @Project_name:xxxxxxx * @date:2020/1/14 9:46 * @email:hhy_0602@163.com * @description:{todo} */ @Slf4j public class IPInterceptor implements HandlerInterceptor { @Autowired private ProjectTableDao projectTableDao; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("---------- 判斷相關ip"); //先獲取相關需要驗證的ip列表 //過濾ip,若用戶在白名單內,則放行 String ipAddress=IPUtils.getRealIP(request); //所用需要驗證的ip,暫時批量驗證 List<String> listIps = getListIps(); if (listIps == null || listIps.size() == 0 || !listIps.contains(ipAddress) ){ response.getWriter().print("請檢查ip白名單配置是否正確"); return false; } return true; } @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 { } /** * 獲取符合要求的項目 * @return */ public List<String> getListIps(){ /** * 保存最后結果 */ List<String> result = new ArrayList<>(); Map<String,Object> map = new HashMap<>(); map.put("flag","1"); map.put("enabled","1"); List<ProjectTable> projectTables = projectTableDao.selectByMap(map); /** * @author: huhy http://www.cnblogs.com/huhongy/ */ for (ProjectTable projectTable : projectTables) { String ips = projectTable.getIps(); List<String> list = splitStr(ips); result.addAll(list); } return result; } /** * 吧ip拆分 */ public List<String> splitStr(String ips){ List<String> temp = new ArrayList<>(); String[] split = ips.split(","); List<String> list = Arrays.asList(split); /** * @author: huhy http://www.cnblogs.com/huhongy/ */ for (String s : list) { temp.add(s); } return temp; } }
關於防止代理ip,獲取多ip的首位ip
public class IPUtils {
/**
* 獲取用戶真實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);
}
return ip;
}
}
最后一步,注冊攔截器即可:
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ParamInterceptor()).addPathPatterns("/data/wuc/**");
/**
* 指定攔截的相關請求接口
*/
//registry.addInterceptor(new ParamInterceptor()).addPathPatterns("/data/wuc/**");
}
}
到這,關於ip白名單的功能就完成了。有興趣的可以試一下
