feat: 连接列表显示客户端真实 IP,支持反代和 CDN 场景
新增可配置的 real_ip_headers(默认 CF-Connecting-IP > X-Real-IP > X-Forwarded-For 降级取值),trusted_proxies 用于 gin 代理信任链。 WebSocket 连接建立时捕获真实 IP 并在 /profile 和 /admin 连接列表展示, 登录会话 IP 同步改用真实 IP。
This commit is contained in:
@@ -154,6 +154,7 @@ export default {
|
||||
user: 'User',
|
||||
ipv4: 'IPv4',
|
||||
ipv6: 'IPv6',
|
||||
realIp: 'Real IP',
|
||||
connectTime: 'Connected At',
|
||||
noOnlineClients: 'No online clients',
|
||||
staticIpReservation: 'Static IP Reservation',
|
||||
|
||||
@@ -153,6 +153,7 @@ export default {
|
||||
user: '用户',
|
||||
ipv4: 'IPv4',
|
||||
ipv6: 'IPv6',
|
||||
realIp: '真实 IP',
|
||||
connectTime: '连接时间',
|
||||
noOnlineClients: '暂无在线客户端',
|
||||
staticIpReservation: '静态 IP 预留',
|
||||
|
||||
@@ -25,6 +25,7 @@ interface ClientInfo {
|
||||
username: string
|
||||
ip: string
|
||||
ip6?: string
|
||||
real_ip: string
|
||||
connected_at: string
|
||||
rx_bytes: number
|
||||
tx_bytes: number
|
||||
@@ -215,6 +216,7 @@ function handleStatClick(route: string) {
|
||||
<thead>
|
||||
<tr class="border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50">
|
||||
<th class="px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400">{{ t('vpn.user') }}</th>
|
||||
<th class="px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400">{{ t('vpn.realIp') }}</th>
|
||||
<th class="px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400">{{ t('vpn.ipv4') }}</th>
|
||||
<th class="px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400">{{ t('vpn.ipv6') }}</th>
|
||||
<th class="px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400">{{ t('vpn.connectTime') }}</th>
|
||||
@@ -225,10 +227,11 @@ function handleStatClick(route: string) {
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-if="!vpnClients.length">
|
||||
<td colspan="7" class="px-6 py-6 text-center text-gray-400">{{ t('vpn.noOnlineClients') }}</td>
|
||||
<td colspan="8" class="px-6 py-6 text-center text-gray-400">{{ t('vpn.noOnlineClients') }}</td>
|
||||
</tr>
|
||||
<tr v-for="(c, i) in vpnClients" :key="i" class="border-b border-gray-100 dark:border-gray-700/50">
|
||||
<td class="px-6 py-3 text-gray-900 dark:text-white font-medium">{{ c.username }}</td>
|
||||
<td class="px-6 py-3 text-gray-700 dark:text-gray-300">{{ c.real_ip || '-' }}</td>
|
||||
<td class="px-6 py-3 text-gray-700 dark:text-gray-300">{{ c.ip }}</td>
|
||||
<td class="px-6 py-3 text-gray-700 dark:text-gray-300">{{ c.ip6 || '-' }}</td>
|
||||
<td class="px-6 py-3 text-gray-500 dark:text-gray-400">{{ c.connected_at }}</td>
|
||||
|
||||
@@ -12,6 +12,7 @@ const { t } = useI18n()
|
||||
interface VpnConnection {
|
||||
ip: string
|
||||
ip6?: string
|
||||
real_ip: string
|
||||
connected_at: string
|
||||
}
|
||||
const vpnConnections = ref<VpnConnection[]>([])
|
||||
@@ -155,6 +156,7 @@ async function handleChangePassword() {
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50">
|
||||
<th class="px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400">{{ t('vpn.realIp') }}</th>
|
||||
<th class="px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400">{{ t('vpn.ipv4') }}</th>
|
||||
<th class="px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400">{{ t('vpn.ipv6') }}</th>
|
||||
<th class="px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400">{{ t('vpn.connectTime') }}</th>
|
||||
@@ -162,9 +164,10 @@ async function handleChangePassword() {
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-if="!vpnConnections.length">
|
||||
<td colspan="3" class="px-6 py-6 text-center text-gray-400">{{ t('profile.noConnections') }}</td>
|
||||
<td colspan="4" class="px-6 py-6 text-center text-gray-400">{{ t('profile.noConnections') }}</td>
|
||||
</tr>
|
||||
<tr v-for="(c, i) in vpnConnections" :key="i" class="border-b border-gray-100 dark:border-gray-700/50">
|
||||
<td class="px-6 py-3 text-gray-700 dark:text-gray-300">{{ c.real_ip || '-' }}</td>
|
||||
<td class="px-6 py-3 text-gray-700 dark:text-gray-300">{{ c.ip }}</td>
|
||||
<td class="px-6 py-3 text-gray-700 dark:text-gray-300">{{ c.ip6 || '-' }}</td>
|
||||
<td class="px-6 py-3 text-gray-500 dark:text-gray-400">{{ c.connected_at }}</td>
|
||||
|
||||
@@ -23,6 +23,7 @@ interface ClientInfo {
|
||||
username: string
|
||||
ip: string
|
||||
ip6?: string
|
||||
real_ip: string
|
||||
connected_at: string
|
||||
}
|
||||
interface Status {
|
||||
|
||||
Reference in New Issue
Block a user