package cc.mrbird.febs.firewall.controller; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.firewall.entity.FirewallAccessLog; import cc.mrbird.febs.firewall.service.IFirewallRuleService; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.servlet.ServletUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; /** * 公开访问追踪API(无需登录) *

* 前端 SPA 页面加载时调用此接口记录访问。 * Nginx 需配置 proxy_set_header 传递国家: *

 *   proxy_set_header X-Real-IP $remote_addr;
 *   proxy_set_header X-Geo-Country $geoip_country_code;
 * 
* * @author auto-generated * @date 2026-07-31 */ @Slf4j @RestController @RequestMapping("api/track") @RequiredArgsConstructor public class ApiTrackController { private final IFirewallRuleService firewallRuleService; /** ISO 3166-1 alpha-2 国家编码 → 国家名称 */ private static final Map COUNTRY_MAP = new HashMap<>(); static { COUNTRY_MAP.put("CN", "中国"); COUNTRY_MAP.put("US", "美国"); COUNTRY_MAP.put("GB", "英国"); COUNTRY_MAP.put("JP", "日本"); COUNTRY_MAP.put("KR", "韩国"); COUNTRY_MAP.put("DE", "德国"); COUNTRY_MAP.put("FR", "法国"); COUNTRY_MAP.put("CA", "加拿大"); COUNTRY_MAP.put("AU", "澳大利亚"); COUNTRY_MAP.put("BR", "巴西"); COUNTRY_MAP.put("IN", "印度"); COUNTRY_MAP.put("RU", "俄罗斯"); COUNTRY_MAP.put("SG", "新加坡"); COUNTRY_MAP.put("MY", "马来西亚"); COUNTRY_MAP.put("TH", "泰国"); COUNTRY_MAP.put("VN", "越南"); COUNTRY_MAP.put("ID", "印度尼西亚"); COUNTRY_MAP.put("PH", "菲律宾"); COUNTRY_MAP.put("IT", "意大利"); COUNTRY_MAP.put("ES", "西班牙"); COUNTRY_MAP.put("NL", "荷兰"); COUNTRY_MAP.put("SE", "瑞典"); COUNTRY_MAP.put("CH", "瑞士"); COUNTRY_MAP.put("HK", "中国香港"); COUNTRY_MAP.put("TW", "中国台湾"); COUNTRY_MAP.put("MO", "中国澳门"); COUNTRY_MAP.put("AE", "阿联酋"); COUNTRY_MAP.put("SA", "沙特阿拉伯"); COUNTRY_MAP.put("TR", "土耳其"); COUNTRY_MAP.put("PK", "巴基斯坦"); COUNTRY_MAP.put("BD", "孟加拉国"); COUNTRY_MAP.put("NG", "尼日利亚"); COUNTRY_MAP.put("ZA", "南非"); COUNTRY_MAP.put("EG", "埃及"); COUNTRY_MAP.put("MX", "墨西哥"); COUNTRY_MAP.put("AR", "阿根廷"); COUNTRY_MAP.put("CL", "智利"); COUNTRY_MAP.put("CO", "哥伦比亚"); COUNTRY_MAP.put("PE", "秘鲁"); COUNTRY_MAP.put("PL", "波兰"); COUNTRY_MAP.put("UA", "乌克兰"); COUNTRY_MAP.put("BE", "比利时"); COUNTRY_MAP.put("AT", "奥地利"); COUNTRY_MAP.put("IE", "爱尔兰"); COUNTRY_MAP.put("NO", "挪威"); COUNTRY_MAP.put("DK", "丹麦"); COUNTRY_MAP.put("FI", "芬兰"); COUNTRY_MAP.put("PT", "葡萄牙"); COUNTRY_MAP.put("CZ", "捷克"); COUNTRY_MAP.put("RO", "罗马尼亚"); COUNTRY_MAP.put("GR", "希腊"); COUNTRY_MAP.put("HU", "匈牙利"); COUNTRY_MAP.put("IL", "以色列"); COUNTRY_MAP.put("IR", "伊朗"); COUNTRY_MAP.put("IQ", "伊拉克"); COUNTRY_MAP.put("MM", "缅甸"); COUNTRY_MAP.put("KH", "柬埔寨"); COUNTRY_MAP.put("LA", "老挝"); COUNTRY_MAP.put("NP", "尼泊尔"); COUNTRY_MAP.put("LK", "斯里兰卡"); COUNTRY_MAP.put("KZ", "哈萨克斯坦"); COUNTRY_MAP.put("UZ", "乌兹别克斯坦"); COUNTRY_MAP.put("NZ", "新西兰"); COUNTRY_MAP.put("KE", "肯尼亚"); COUNTRY_MAP.put("ET", "埃塞俄比亚"); COUNTRY_MAP.put("MA", "摩洛哥"); COUNTRY_MAP.put("DZ", "阿尔及利亚"); COUNTRY_MAP.put("TN", "突尼斯"); } /** * 根据国家编码获取名称 */ public static String getCountryName(String code) { if (StrUtil.isBlank(code)) { return null; } return COUNTRY_MAP.getOrDefault(code.toUpperCase(), code); } @GetMapping("visit") public FebsResponse trackVisit(HttpServletRequest request) { try { String countryCode = request.getHeader("X-Geo-Country"); FirewallAccessLog accessLog = new FirewallAccessLog(); accessLog.setIp(ServletUtil.getClientIP(request)); accessLog.setCountryCode(countryCode); accessLog.setCountryName(getCountryName(countryCode)); accessLog.setUserAgent(request.getHeader("User-Agent")); accessLog.setRequestUri(request.getHeader("Referer")); accessLog.setIsBlocked(0); firewallRuleService.recordAccess(accessLog); return new FebsResponse().success(); } catch (Exception e) { log.error("访问追踪记录失败", e); return new FebsResponse().fail().message("记录失败"); } } }