feat(openvpn): suggest available OIDC ports and add deployment assets
This commit is contained in:
1 parent
d6a9a92ad0
commit
003f755b37
14 files changed
+244
-7
No files matched your search
@@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<title>VPN 专线管理平台</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop stop-color="#153a75"/>
|
||||
<stop offset="1" stop-color="#087ca5"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="64" height="64" rx="15" fill="url(#bg)"/>
|
||||
<path d="M32 8 51 16v13c0 13-7.5 22-19 28C20.5 51 13 42 13 29V16Z" fill="#fff"/>
|
||||
<path d="M32 13 46 19v10c0 10-5 17-14 22-9-5-14-12-14-22V19Z" fill="#0b568c"/>
|
||||
<path d="M22 25h7l4 13 5-13h5" fill="none" stroke="#66e2df" stroke-linecap="round" stroke-linejoin="round" stroke-width="4"/>
|
||||
<circle cx="22" cy="25" r="2.5" fill="#fff"/>
|
||||
<circle cx="43" cy="25" r="2.5" fill="#fff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 692 B |
@@ -30,7 +30,11 @@
|
||||
<div class="field-tip">{{ $t('oidcGuide.baseTip') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('oidcGuide.listenPort')">
|
||||
<el-input-number v-model="config.oidc_http_port" :min="1024" :max="65535" />
|
||||
<div class="port-controls">
|
||||
<el-button :disabled="portLoading || !config.oidc_http_port || config.oidc_http_port <= 1024" @click="stepPort(-1)">−</el-button>
|
||||
<el-input-number v-model="config.oidc_http_port" :controls="false" :min="1024" :max="65535" :disabled="portLoading" @change="changePort" />
|
||||
<el-button :disabled="portLoading || !config.oidc_http_port || config.oidc_http_port >= 65535" @click="stepPort(1)">+</el-button>
|
||||
</div>
|
||||
<div class="field-tip">{{ $t('oidcGuide.portTip') }}</div>
|
||||
</el-form-item>
|
||||
<el-alert type="warning" :closable="false" class="guide-alert" :title="$t('oidcGuide.callbackTitle')">
|
||||
@@ -44,9 +48,38 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import api from '../api'
|
||||
|
||||
const props = defineProps({ config: { type: Object, required: true }, editing: { type: Boolean, default: false } })
|
||||
const { t } = useI18n()
|
||||
const portLoading = ref(false)
|
||||
async function requestPort(from, direction, previous = null) {
|
||||
portLoading.value = true
|
||||
try {
|
||||
const params = from == null ? {} : { from, direction }
|
||||
const { data } = await api.get('/tunnels/openvpn/oidc-port', { params })
|
||||
props.config.oidc_http_port = data.port
|
||||
} catch (error) {
|
||||
if (Number.isInteger(previous)) props.config.oidc_http_port = previous
|
||||
ElMessage.error(error.response?.data?.error || t('oidcGuide.portLookupFailed'))
|
||||
} finally {
|
||||
portLoading.value = false
|
||||
}
|
||||
}
|
||||
function stepPort(direction) {
|
||||
const previous = Number(props.config.oidc_http_port)
|
||||
requestPort(previous + direction, direction, previous)
|
||||
}
|
||||
function changePort(value, previous) {
|
||||
if (!Number.isInteger(value) || value === previous) return
|
||||
requestPort(value, value < previous ? -1 : 1, previous)
|
||||
}
|
||||
onMounted(() => {
|
||||
if (!props.editing) requestPort(null, 1)
|
||||
})
|
||||
const callbackUrl = computed(() => `${(props.config.oidc_base_url || 'https://vpn-login.example.com').replace(/\/+$/, '')}/oauth2/callback`)
|
||||
const guideStep = computed(() => !props.config.oidc_client_id ? 0
|
||||
: !props.config.oidc_issuer || (!props.config.oidc_client_secret && !props.editing) ? 1
|
||||
@@ -61,6 +94,7 @@ const guideStep = computed(() => !props.config.oidc_client_id ? 0
|
||||
.guide-alert p { margin: 8px 0 0; line-height: 1.5; }
|
||||
.guide-alert ol { padding-left: 20px; line-height: 1.7; }
|
||||
.field-tip { margin-top: 4px; color: var(--text-secondary); font-size: 12px; line-height: 1.5; }
|
||||
.port-controls { display: flex; gap: 6px; align-items: center; }
|
||||
code { overflow-wrap: anywhere; }
|
||||
@media (max-width: 720px) { .guide-steps { overflow-x: auto; justify-content: flex-start; } .guide-steps :deep(.el-step) { min-width: 120px; } }
|
||||
</style>
|
||||
@@ -248,7 +248,8 @@
|
||||
"baseUrl": "Public sign-in URL",
|
||||
"baseTip": "Use a dedicated HTTPS root URL reachable before VPN connection. Give each OIDC tunnel its own endpoint.",
|
||||
"listenPort": "Local auth service port",
|
||||
"portTip": "The service listens on 127.0.0.1 only; each tunnel needs a distinct port.",
|
||||
"portTip": "Listens only on 127.0.0.1; no public access needed. New tunnels increment from 19090; +/- and manual entry skip configured and locally occupied ports.",
|
||||
"portLookupFailed": "Could not find an available port. Retry or enter one manually.",
|
||||
"callbackTitle": "Register this callback with the final OIDC provider",
|
||||
"callbackTip": "With an identity broker, register this URL in the broker's OIDC client, and register the broker's upstream callback in Feishu. Reverse proxy the public endpoint to 127.0.0.1:{port}; :18080 does not handle this callback.",
|
||||
"testTip": "Install openvpn-auth-oauth2 and OpenVPN ≥ 2.6.2, then test with a WebAuth-capable client (e.g. OpenVPN Community for Windows or Tunnelblick/Viscosity for macOS). OpenVPN Connect v3 needs individual testing.",
|
||||
|
||||
@@ -248,7 +248,8 @@
|
||||
"baseUrl": "认证入口公网地址",
|
||||
"baseTip": "填写独立 HTTPS 域名根地址;客户端未连上 VPN 时也必须能访问。每条 OIDC 专线使用独立入口。",
|
||||
"listenPort": "本机认证服务端口",
|
||||
"portTip": "认证服务仅监听 127.0.0.1;多条专线各用不同端口。",
|
||||
"portTip": "仅监听本机 127.0.0.1,无需公网开放。新建专线自动从 19090 起递增;加减或手动输入会跳过已配置和本机正在监听的端口。",
|
||||
"portLookupFailed": "无法获取可用端口,请稍后重试或手动选择",
|
||||
"callbackTitle": "在最终 OIDC 身份提供方的客户端中登记此回调地址",
|
||||
"callbackTip": "如果通过身份代理接入飞书,本地址登记在代理的 OIDC 客户端中,飞书应用应登记代理的上游回调。将公网入口的所有路径反向代理至本机 127.0.0.1:{port};不由 :18080 处理。",
|
||||
"testTip": "安装 openvpn-auth-oauth2 与 OpenVPN ≥ 2.6.2 后启动专线;使用支持 WebAuth 的客户端试连(如 Windows OpenVPN Community、macOS Tunnelblick/Viscosity)。OpenVPN Connect v3 部分兼容,须实测。",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="login-left">
|
||||
<div class="brand-content fade-in">
|
||||
<div class="brand-logo">
|
||||
<el-icon :size="32" color="#7dd3fc"><Lock /></el-icon>
|
||||
<img src="/favicon.svg" alt="" width="40" height="40" />
|
||||
</div>
|
||||
<h1 class="brand-title">{{ $t('login.title') }}</h1>
|
||||
<p class="brand-subtitle">{{ $t('login.subtitle') }}</p>
|
||||
|
||||
@@ -162,6 +162,7 @@ async function save() {
|
||||
for (const key of ['oidc_issuer', 'oidc_client_id', 'oidc_base_url', ...(originalAuthMode.value === 'oidc' ? [] : ['oidc_client_secret'])]) {
|
||||
if (!form.value.config[key]) return ElMessage.warning(t('oidcGuide.fillRequired'))
|
||||
}
|
||||
if (!form.value.config.oidc_http_port) return ElMessage.warning(t('oidcGuide.portLookupFailed'))
|
||||
}
|
||||
trafficMode.value = trafficMode.value
|
||||
if (isOpenVPN.value && routeListRef.value && !routeListRef.value.validate()) return
|
||||
|
||||
@@ -233,6 +233,7 @@ async function create() {
|
||||
for (const key of ['oidc_issuer', 'oidc_client_id', 'oidc_client_secret', 'oidc_base_url']) {
|
||||
if (!form.value.config[key]) return ElMessage.warning(t('oidcGuide.fillRequired'))
|
||||
}
|
||||
if (!form.value.config.oidc_http_port) return ElMessage.warning(t('oidcGuide.portLookupFailed'))
|
||||
}
|
||||
trafficMode.value = trafficMode.value
|
||||
if (isOpenVPN.value && routeListRef.value && !routeListRef.value.validate()) return
|
||||
|
||||
Reference in new issue
Block a user