初次提交
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import type { H3Event } from 'h3'
|
||||
import { getHeaders } from 'h3'
|
||||
|
||||
/**
|
||||
* 获取客户端IP地址
|
||||
* @param event H3Event对象
|
||||
* @returns 客户端IP地址
|
||||
*/
|
||||
export function getClientIP(event: H3Event): string {
|
||||
// 尝试从各种可能的头部获取真实IP
|
||||
const headers = getHeaders(event)
|
||||
|
||||
// 按优先级检查各种IP头部
|
||||
const ipHeaders = [
|
||||
'x-forwarded-for',
|
||||
'x-real-ip',
|
||||
'x-client-ip',
|
||||
'cf-connecting-ip', // Cloudflare
|
||||
'x-forwarded',
|
||||
'forwarded-for',
|
||||
'forwarded'
|
||||
]
|
||||
|
||||
for (const header of ipHeaders) {
|
||||
const value = headers[header]
|
||||
if (value) {
|
||||
// x-forwarded-for 可能包含多个IP,取第一个
|
||||
const ip = Array.isArray(value) ? value[0] : value
|
||||
const firstIP = ip.split(',')[0].trim()
|
||||
if (firstIP && isValidIP(firstIP)) {
|
||||
return firstIP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到,直接从连接信息获取
|
||||
|
||||
// 从连接信息获取IP(备用方法)
|
||||
const remoteAddress = event.node.req.socket?.remoteAddress
|
||||
if (remoteAddress) {
|
||||
// 移除IPv6映射的IPv4前缀
|
||||
const cleanIP = remoteAddress.replace(/^::ffff:/, '')
|
||||
if (isValidIP(cleanIP)) {
|
||||
return cleanIP
|
||||
}
|
||||
}
|
||||
|
||||
return 'unknown'
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证IP地址格式是否有效
|
||||
* @param ip IP地址字符串
|
||||
* @returns 是否为有效IP
|
||||
*/
|
||||
function isValidIP(ip: string): boolean {
|
||||
// 简单的IP格式验证
|
||||
const ipv4Regex =
|
||||
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
||||
const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/
|
||||
|
||||
// 基本格式验证
|
||||
if (!ipv4Regex.test(ip) && !ipv6Regex.test(ip)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 排除明显无效的IP
|
||||
if (ip === '0.0.0.0' || ip === '::') {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化IP地址用于邮件显示
|
||||
* @param ip IP地址
|
||||
* @returns 格式化后的IP地址字符串
|
||||
*/
|
||||
export function formatIPForEmail(ip: string): string {
|
||||
if (!ip || ip === 'unknown') {
|
||||
return '未知'
|
||||
}
|
||||
|
||||
// 如果是本地IP,显示为本地访问
|
||||
if (
|
||||
ip === '127.0.0.1' ||
|
||||
ip === '::1' ||
|
||||
ip.startsWith('192.168.') ||
|
||||
ip.startsWith('10.') ||
|
||||
ip.startsWith('172.')
|
||||
) {
|
||||
return `${ip} (本地网络)`
|
||||
}
|
||||
|
||||
return ip
|
||||
}
|
||||
Reference in New Issue
Block a user