feat(web): add OIDC SSO login support (#1943)

This commit is contained in:
Mg Pig
2026-03-03 18:23:31 +08:00
committed by GitHub
parent d4ff0b1767
commit ff24332e23
16 changed files with 1300 additions and 156 deletions
+42 -3
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { Card, InputText, Password, Button, AutoComplete } from 'primevue';
import { useRouter } from 'vue-router';
import { useToast } from 'primevue/usetoast';
@@ -68,8 +68,43 @@ const apiHostSearch = async (event: { query: string }) => {
});
}
onMounted(() => {
const oidcEnabled = ref(false);
const lastCheckedHost = ref('');
const oidcCheckTimer = ref<ReturnType<typeof setTimeout> | null>(null);
const checkOidcConfig = () => {
if (oidcCheckTimer.value) clearTimeout(oidcCheckTimer.value);
oidcCheckTimer.value = setTimeout(async () => {
const host = apiHost.value;
if (host === lastCheckedHost.value) return;
const enabled = (await new ApiClient(host).getOidcConfig()).enabled;
// If host changes while request is in-flight, do not overwrite UI state.
if (apiHost.value !== host) return;
lastCheckedHost.value = host;
oidcEnabled.value = enabled;
}, 300);
};
watch(apiHost, () => {
checkOidcConfig();
});
const onSsoLogin = () => {
saveApiHost(apiHost.value);
localStorage.setItem('apiHost', btoa(apiHost.value));
window.location.href = api.value.oidcLoginUrl();
};
onMounted(() => {
checkOidcConfig();
});
onBeforeUnmount(() => {
if (oidcCheckTimer.value) {
clearTimeout(oidcCheckTimer.value);
oidcCheckTimer.value = null;
}
});
</script>
@@ -104,6 +139,10 @@ onMounted(() => {
<Button :label="t('web.login.register')" type="button" class="w-full"
@click="saveApiHost(apiHost); $router.replace({ name: 'register' })" severity="secondary" />
</div>
<div v-if="oidcEnabled" class="flex items-center justify-between">
<Button :label="t('web.login.sso_login')" type="button" class="w-full" severity="info"
@click="onSsoLogin" />
</div>
</form>
<form v-else @submit.prevent="onRegister" class="space-y-4">
@@ -144,4 +183,4 @@ onMounted(() => {
</div>
</template>
<style scoped></style>
<style scoped></style>
+17
View File
@@ -6,6 +6,10 @@ export interface ValidateConfigResponse {
toml_config: string;
}
export interface OidcConfigResponse {
enabled: boolean;
}
// 定义接口返回的数据结构
export interface LoginResponse {
success: boolean;
@@ -174,6 +178,19 @@ export class ApiClient {
return this.client.defaults.baseURL + '/auth/captcha';
}
public async getOidcConfig(): Promise<OidcConfigResponse> {
try {
const response = await this.client.get<any, OidcConfigResponse>('/auth/oidc/config');
return response;
} catch (error) {
return { enabled: false };
}
}
public oidcLoginUrl() {
return this.client.defaults.baseURL + '/auth/oidc/login';
}
public get_remote_client(machine_id: string): Api.RemoteClient {
return new WebRemoteClient(machine_id, this.client);
}