sync authserver sso integrations

This commit is contained in:
mac
2026-07-14 17:37:08 +08:00
parent aa06c05d88
commit 8c7a1ae9ea
12 changed files with 490 additions and 43 deletions
+25
View File
@@ -53,6 +53,31 @@ server {
proxy_read_timeout 60s;
}
location /auth/.well-known/ {
proxy_pass http://authserver-backend:8083;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
location /internal/clouddm/ {
proxy_pass http://open-cdm.db.svc.cluster.local:8222/;
proxy_http_version 1.1;
proxy_set_header Host 218.11.5.223:30009;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host 218.11.5.223:30009;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto http;
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
location /auth/ {
try_files $uri $uri/ /auth/index.html;
}
+60 -17
View File
@@ -4,6 +4,7 @@ import { computed, onMounted, ref } from 'vue'
const TOKEN_KEY = 'authserver_token'
const SSO_LOGIN_PATH = '/auth/api/v1/login/internal-sso'
const WAYEN_LOGIN_PATH = '/auth/api/v1/wayen/login'
const CLOUDDM_LOGIN_PATH = '/auth/api/v1/clouddm/login'
const token = ref(localStorage.getItem(TOKEN_KEY) || '')
const currentUser = ref(null)
@@ -11,6 +12,7 @@ const message = ref('')
const loading = ref(false)
const redirectingToSSO = ref(false)
const wayenLoading = ref(false)
const clouddmLoading = ref(false)
const isAuthed = computed(() => Boolean(token.value))
const currentUserLabel = computed(() => {
@@ -26,20 +28,24 @@ function clearAuth() {
localStorage.removeItem(TOKEN_KEY)
}
function relayState(openWayen = false) {
function relayState(openApp = '') {
const url = new URL(window.location.href)
if (openWayen) {
url.searchParams.delete('open_wayen')
url.searchParams.delete('open_app')
if (openApp === 'wayen') {
url.searchParams.set('open_wayen', '1')
} else if (openApp) {
url.searchParams.set('open_app', openApp)
}
return `${url.pathname}${url.search}${url.hash}` || '/'
}
function ssoLogin({ openWayen = false } = {}) {
function ssoLogin({ openApp = '' } = {}) {
if (redirectingToSSO.value) {
return
}
redirectingToSSO.value = true
window.location.assign(`${SSO_LOGIN_PATH}?relay_state=${encodeURIComponent(relayState(openWayen))}`)
window.location.assign(`${SSO_LOGIN_PATH}?relay_state=${encodeURIComponent(relayState(openApp))}`)
}
async function api(path, options = {}) {
@@ -55,7 +61,7 @@ async function api(path, options = {}) {
if (!response.ok) {
if (response.status === 401) {
clearAuth()
ssoLogin({ openWayen: true })
ssoLogin()
}
const error = new Error(data.error || `HTTP ${response.status}`)
error.status = response.status
@@ -103,7 +109,7 @@ async function openWayen() {
if (!response.ok) {
if (response.status === 401) {
clearAuth()
ssoLogin({ openWayen: true })
ssoLogin({ openApp: 'wayen' })
}
throw new Error(data.error || `HTTP ${response.status}`)
}
@@ -118,26 +124,59 @@ async function openWayen() {
}
}
async function openCloudDM() {
clouddmLoading.value = true
message.value = ''
try {
const response = await fetch(CLOUDDM_LOGIN_PATH, {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token.value}`,
},
credentials: 'include',
})
const data = await response.json().catch(() => ({}))
if (!response.ok) {
if (response.status === 401) {
clearAuth()
ssoLogin({ openApp: 'clouddm' })
}
throw new Error(data.error || `HTTP ${response.status}`)
}
if (!data.target_url) {
throw new Error('CloudDM 跳转地址为空')
}
window.location.assign(data.target_url)
} catch (error) {
message.value = error.message
} finally {
clouddmLoading.value = false
}
}
onMounted(async () => {
const url = new URL(window.location.href)
const ssoToken = url.searchParams.get('sso_token')
const shouldOpenWayen = url.searchParams.get('open_wayen') === '1'
const openApp = url.searchParams.get('open_wayen') === '1' ? 'wayen' : url.searchParams.get('open_app')
if (ssoToken) {
token.value = ssoToken
localStorage.setItem(TOKEN_KEY, ssoToken)
url.searchParams.delete('sso_token')
url.searchParams.delete('open_wayen')
url.searchParams.delete('open_app')
window.history.replaceState({}, '', `${url.pathname}${url.search}${url.hash}`)
}
if (!token.value) {
ssoLogin({ openWayen: true })
ssoLogin()
return
}
await run(async () => {
await loadMe()
}, '已就绪')
if (shouldOpenWayen) {
if (openApp === 'wayen') {
await openWayen()
} else if (openApp === 'clouddm') {
await openCloudDM()
}
})
</script>
@@ -147,17 +186,17 @@ onMounted(async () => {
<section class="login-panel">
<div>
<p class="eyebrow">AuthServer</p>
<h1>Wayen 登录入口</h1>
<h1>应用入口</h1>
</div>
<p class="message">正在跳转到 SSO 登录...</p>
</section>
</main>
<main v-else class="wayen-page">
<header class="wayen-header">
<main v-else class="app-page">
<header class="app-header">
<div>
<p class="eyebrow">AuthServer</p>
<h1>Wayen</h1>
<h1>应用入口</h1>
</div>
<div class="user-block">
<span>{{ currentUserLabel }}</span>
@@ -165,10 +204,14 @@ onMounted(async () => {
</div>
</header>
<section class="wayen-main">
<button class="wayen-button" type="button" :disabled="wayenLoading" @click="openWayen">
<span class="wayen-icon" aria-hidden="true">W</span>
<span class="wayen-title">Wayen</span>
<section class="app-main">
<button class="app-button wayen-button" type="button" :disabled="wayenLoading" @click="openWayen">
<span class="app-icon wayen-icon" aria-hidden="true">W</span>
<span class="app-title">Wayen</span>
</button>
<button class="app-button clouddm-button" type="button" :disabled="clouddmLoading" @click="openCloudDM">
<span class="app-icon clouddm-icon" aria-hidden="true">C</span>
<span class="app-title">CloudDM</span>
</button>
<p v-if="message" class="message">{{ message }}</p>
</section>
+19 -12
View File
@@ -98,7 +98,7 @@ h1 {
font-size: 13px;
}
.wayen-page {
.app-page {
min-height: 100vh;
display: grid;
grid-template-rows: auto 1fr;
@@ -107,7 +107,7 @@ h1 {
#f5f7fb;
}
.wayen-header {
.app-header {
display: flex;
align-items: center;
justify-content: space-between;
@@ -118,7 +118,7 @@ h1 {
backdrop-filter: blur(10px);
}
.wayen-main {
.app-main {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 360px));
justify-content: center;
@@ -127,7 +127,7 @@ h1 {
padding: 32px 20px;
}
.wayen-button {
.app-button {
width: min(280px, 78vw);
aspect-ratio: 1;
display: grid;
@@ -140,27 +140,34 @@ h1 {
box-shadow: 0 18px 50px rgb(43 57 84 / 12%);
}
.wayen-button:hover:not(:disabled),
.wayen-button:focus-visible {
.app-button:hover:not(:disabled),
.app-button:focus-visible {
border-color: #1b64d8;
box-shadow: 0 22px 60px rgb(27 100 216 / 18%);
outline: none;
}
.wayen-icon {
.app-icon {
width: 112px;
height: 112px;
display: grid;
place-items: center;
border-radius: 28px;
background: #1b64d8;
color: #ffffff;
font-size: 64px;
font-weight: 800;
line-height: 1;
}
.wayen-title {
.wayen-icon {
background: #1b64d8;
}
.clouddm-icon {
background: #0f7b6c;
}
.app-title {
color: #172033;
font-size: 22px;
font-weight: 750;
@@ -175,7 +182,7 @@ h1 {
}
@media (max-width: 560px) {
.wayen-header {
.app-header {
align-items: flex-start;
flex-direction: column;
padding: 18px 20px;
@@ -186,14 +193,14 @@ h1 {
justify-content: space-between;
}
.wayen-icon {
.app-icon {
width: 92px;
height: 92px;
border-radius: 22px;
font-size: 52px;
}
.wayen-main {
.app-main {
grid-template-columns: 1fr;
}
}