mirror of
https://github.com/rustfs/console.git
synced 2026-08-30 17:14:47 +08:00
fix:login page route
This commit is contained in:
+34
-23
@@ -1,6 +1,6 @@
|
||||
import type { AwsCredentialIdentity, AwsCredentialIdentityProvider } from "@aws-sdk/types";
|
||||
import { getStsToken } from "~/lib/sts";
|
||||
import type { SiteConfig } from "~/types/config";
|
||||
import type { AwsCredentialIdentity, AwsCredentialIdentityProvider } from '@aws-sdk/types';
|
||||
import { getStsToken } from '~/lib/sts';
|
||||
import type { SiteConfig } from '~/types/config';
|
||||
|
||||
interface Credentials {
|
||||
AccessKeyId?: string;
|
||||
@@ -10,48 +10,59 @@ interface Credentials {
|
||||
}
|
||||
|
||||
export function useAuth() {
|
||||
const store = useLocalStorage('auth.credentials', {})
|
||||
const store = useLocalStorage('auth.credentials', {});
|
||||
|
||||
const setCredentials = (credentials: Credentials) => {
|
||||
store.value = credentials
|
||||
}
|
||||
store.value = credentials;
|
||||
};
|
||||
|
||||
const getCredentials = () => {
|
||||
if (!isValidCredentials(store.value)) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
return store.value
|
||||
}
|
||||
return store.value;
|
||||
};
|
||||
|
||||
const isExpired = (expiration: string) => expiration ? new Date(expiration) < new Date() : false
|
||||
const isExpired = (expiration: string) =>
|
||||
expiration ? new Date(expiration) < new Date() : false;
|
||||
|
||||
const isValidCredentials = (credentials: Credentials) => {
|
||||
return !!credentials?.AccessKeyId && !!credentials?.SecretAccessKey && !!credentials?.SessionToken && credentials?.Expiration && !isExpired(credentials.Expiration)
|
||||
}
|
||||
return (
|
||||
!!credentials?.AccessKeyId &&
|
||||
!!credentials?.SecretAccessKey &&
|
||||
!!credentials?.SessionToken &&
|
||||
credentials?.Expiration &&
|
||||
!isExpired(credentials.Expiration)
|
||||
);
|
||||
};
|
||||
|
||||
const login = async (
|
||||
credentials: AwsCredentialIdentity | AwsCredentialIdentityProvider,
|
||||
customConfig?: SiteConfig
|
||||
) => {
|
||||
const credentialsResponse = await getStsToken(credentials, 'arn:aws:iam::*:role/Admin', customConfig)
|
||||
const credentialsResponse = await getStsToken(
|
||||
credentials,
|
||||
'arn:aws:iam::*:role/Admin',
|
||||
customConfig
|
||||
);
|
||||
|
||||
setCredentials({
|
||||
...credentialsResponse,
|
||||
Expiration: credentialsResponse.Expiration?.toISOString()
|
||||
})
|
||||
Expiration: credentialsResponse.Expiration?.toISOString(),
|
||||
});
|
||||
|
||||
return credentialsResponse
|
||||
}
|
||||
return credentialsResponse;
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
store.value = {}
|
||||
}
|
||||
store.value = {};
|
||||
};
|
||||
|
||||
const logoutAndRedirect = () => {
|
||||
logout()
|
||||
window.location.href = '/auth/login'
|
||||
}
|
||||
logout();
|
||||
window.location.href = '/rustfs/console/auth/login';
|
||||
};
|
||||
|
||||
return {
|
||||
login,
|
||||
@@ -59,5 +70,5 @@ export function useAuth() {
|
||||
logoutAndRedirect,
|
||||
credentials: ref<Credentials | undefined>(getCredentials()),
|
||||
isAuthenticated: ref(isValidCredentials(store.value)),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ class ApiClient {
|
||||
const message = useMessage();
|
||||
// 清除登录信息
|
||||
await useAuth().logout();
|
||||
window.location.href = '/auth/login';
|
||||
window.location.href = '/rustfs/console/auth/login';
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+90
-69
@@ -1,106 +1,114 @@
|
||||
<script lang="ts" setup>
|
||||
await setPageLayout('plain')
|
||||
await setPageLayout('plain');
|
||||
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const message = useMessage()
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const message = useMessage();
|
||||
|
||||
const serverHost = ref('')
|
||||
const isValid = ref(false)
|
||||
const serverHost = ref('');
|
||||
const isValid = ref(false);
|
||||
|
||||
const validateAndSave = async () => {
|
||||
try {
|
||||
if (serverHost.value) {
|
||||
// 更宽松的URL验证
|
||||
let urlToValidate = serverHost.value.trim()
|
||||
|
||||
let urlToValidate = serverHost.value.trim();
|
||||
|
||||
// 如果没有协议,自动添加https://
|
||||
if (!urlToValidate.match(/^https?:\/\//)) {
|
||||
urlToValidate = 'https://' + urlToValidate
|
||||
urlToValidate = 'https://' + urlToValidate;
|
||||
}
|
||||
|
||||
|
||||
// 验证URL格式
|
||||
const url = new URL(urlToValidate)
|
||||
console.log('Valid URL:', url.href) // 调试信息
|
||||
|
||||
const url = new URL(urlToValidate);
|
||||
console.log('Valid URL:', url.href); // 调试信息
|
||||
|
||||
// 保存原始输入(如果用户没输入协议,就保存添加了协议的版本)
|
||||
const urlToSave = serverHost.value.match(/^https?:\/\//) ? serverHost.value : urlToValidate
|
||||
localStorage.setItem('rustfs-server-host', urlToSave)
|
||||
|
||||
const urlToSave = serverHost.value.match(/^https?:\/\//) ? serverHost.value : urlToValidate;
|
||||
localStorage.setItem('rustfs-server-host', urlToSave);
|
||||
|
||||
// 如果我们自动添加了协议,更新输入框显示
|
||||
if (!serverHost.value.match(/^https?:\/\//)) {
|
||||
serverHost.value = urlToValidate
|
||||
serverHost.value = urlToValidate;
|
||||
}
|
||||
} else {
|
||||
// 如果为空,清除localStorage,使用默认值
|
||||
localStorage.removeItem('rustfs-server-host')
|
||||
localStorage.removeItem('rustfs-server-host');
|
||||
}
|
||||
|
||||
|
||||
// 清除配置缓存
|
||||
const { configManager } = await import('~/utils/config')
|
||||
configManager.clearCache()
|
||||
|
||||
message.success(t('Server configuration saved successfully'))
|
||||
|
||||
const { configManager } = await import('~/utils/config');
|
||||
configManager.clearCache();
|
||||
|
||||
message.success(t('Server configuration saved successfully'));
|
||||
|
||||
// 延迟后刷新页面并跳转,确保配置完全生效
|
||||
setTimeout(() => {
|
||||
window.location.href = '/auth/login'
|
||||
}, 200)
|
||||
window.location.href = '/rustfs/console/auth/login';
|
||||
}, 200);
|
||||
} catch (error) {
|
||||
console.error('URL validation error:', error) // 调试信息
|
||||
message.error(t('Invalid server address format') + ': ' + (error as Error).message)
|
||||
console.error('URL validation error:', error); // 调试信息
|
||||
message.error(t('Invalid server address format') + ': ' + (error as Error).message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const resetToCurrentHost = async () => {
|
||||
// 清除localStorage中的配置,让系统回到默认状态(使用当前host)
|
||||
localStorage.removeItem('rustfs-server-host')
|
||||
|
||||
localStorage.removeItem('rustfs-server-host');
|
||||
|
||||
// 清除配置缓存
|
||||
const { configManager } = await import('~/utils/config')
|
||||
configManager.clearCache()
|
||||
|
||||
const { configManager } = await import('~/utils/config');
|
||||
configManager.clearCache();
|
||||
|
||||
// 清空输入框,表示使用默认配置
|
||||
serverHost.value = ''
|
||||
|
||||
message.success(t('Reset to default successfully'))
|
||||
|
||||
serverHost.value = '';
|
||||
|
||||
message.success(t('Reset to default successfully'));
|
||||
|
||||
// 延迟后跳转到登录页面,确保配置完全生效
|
||||
setTimeout(() => {
|
||||
window.location.href = '/auth/login'
|
||||
}, 200)
|
||||
}
|
||||
window.location.href = '/rustfs/console/auth/login';
|
||||
}, 200);
|
||||
};
|
||||
|
||||
const skipConfig = () => {
|
||||
router.push('/auth/login')
|
||||
}
|
||||
router.push('/auth/login');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// 检查是否已有配置
|
||||
const saved = localStorage.getItem('rustfs-server-host')
|
||||
const saved = localStorage.getItem('rustfs-server-host');
|
||||
if (saved) {
|
||||
serverHost.value = saved
|
||||
isValid.value = true
|
||||
serverHost.value = saved;
|
||||
isValid.value = true;
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="lg:p-20 flex flex-col items-center justify-center min-h-screen bg-gray-100 dark:bg-neutral-800">
|
||||
<div
|
||||
class="lg:p-20 flex flex-col items-center justify-center min-h-screen bg-gray-100 dark:bg-neutral-800"
|
||||
>
|
||||
<img src="~/assets/backgrounds/scillate.svg" class="absolute inset-0 z-0 opacity-45" alt="" />
|
||||
<div class="flex-1 flex w-full z-10 max-w-7xl lg:max-h-[85vh] shadow-lg rounded-lg overflow-hidden mx-auto dark:bg-neutral-800 dark:border-neutral-700">
|
||||
<div
|
||||
class="flex-1 flex w-full z-10 max-w-7xl lg:max-h-[85vh] shadow-lg rounded-lg overflow-hidden mx-auto dark:bg-neutral-800 dark:border-neutral-700"
|
||||
>
|
||||
<div class="hidden lg:block w-1/2">
|
||||
<auth-heros-static></auth-heros-static>
|
||||
</div>
|
||||
<div class="w-full lg:w-1/2 flex flex-col justify-center items-center bg-white dark:bg-neutral-900 dark:border-neutral-700 relative">
|
||||
<div
|
||||
class="w-full lg:w-1/2 flex flex-col justify-center items-center bg-white dark:bg-neutral-900 dark:border-neutral-700 relative"
|
||||
>
|
||||
<div class="max-w-sm w-full p-4 sm:p-7">
|
||||
<img src="https://rustfs.com/rustfs.logo.svg" class="max-w-28" alt="" />
|
||||
<div class="py-6">
|
||||
<h1 class="block text-2xl font-bold text-gray-800 dark:text-white">{{ t('Server Configuration') }}</h1>
|
||||
<h1 class="block text-2xl font-bold text-gray-800 dark:text-white">
|
||||
{{ t('Server Configuration') }}
|
||||
</h1>
|
||||
<p class="mt-2 text-sm text-gray-600 dark:text-neutral-400">
|
||||
{{ t('Please configure your RustFS server address') }}
|
||||
</p>
|
||||
@@ -111,14 +119,16 @@ onMounted(() => {
|
||||
<form @submit.prevent="validateAndSave" autocomplete="off">
|
||||
<div class="grid gap-y-6">
|
||||
<div>
|
||||
<label for="serverHost" class="block text-sm mb-2 dark:text-white">{{ t('Server Address') }}</label>
|
||||
<label for="serverHost" class="block text-sm mb-2 dark:text-white">{{
|
||||
t('Server Address')
|
||||
}}</label>
|
||||
<div class="text-xs text-gray-500 mb-2">
|
||||
{{ t('Leave empty to use current host as default') }}
|
||||
</div>
|
||||
<n-input
|
||||
v-model:value="serverHost"
|
||||
type="text"
|
||||
:placeholder="t('Please enter server address (e.g., http://localhost:9000)')"
|
||||
<n-input
|
||||
v-model:value="serverHost"
|
||||
type="text"
|
||||
:placeholder="t('Please enter server address (e.g., http://localhost:9000)')"
|
||||
/>
|
||||
<div class="text-xs text-gray-500 mt-1">
|
||||
{{ t('Example: http://localhost:9000 or https://your-domain.com') }}
|
||||
@@ -126,18 +136,26 @@ onMounted(() => {
|
||||
</div>
|
||||
|
||||
<div class="flex gap-3">
|
||||
<button type="submit"
|
||||
class="flex-1 py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex-1 py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none"
|
||||
>
|
||||
{{ t('Save Configuration') }}
|
||||
</button>
|
||||
|
||||
<button type="button" @click="resetToCurrentHost"
|
||||
class="py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-gray-200 bg-white text-gray-800 shadow-sm hover:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-800">
|
||||
|
||||
<button
|
||||
type="button"
|
||||
@click="resetToCurrentHost"
|
||||
class="py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-gray-200 bg-white text-gray-800 shadow-sm hover:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-800"
|
||||
>
|
||||
{{ t('Reset') }}
|
||||
</button>
|
||||
|
||||
<button type="button" @click="skipConfig"
|
||||
class="py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-gray-200 bg-white text-gray-800 shadow-sm hover:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-800">
|
||||
|
||||
<button
|
||||
type="button"
|
||||
@click="skipConfig"
|
||||
class="py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-gray-200 bg-white text-gray-800 shadow-sm hover:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-800"
|
||||
>
|
||||
{{ t('Skip') }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -148,7 +166,10 @@ onMounted(() => {
|
||||
|
||||
<div class="my-8">
|
||||
<p class="text-sm text-gray-600 dark:text-neutral-400">
|
||||
{{ t('Need help?') }} <NuxtLink to="https://docs.rustfs.com" class="text-blue-600 hover:underline">{{ t('View Documentation') }}</NuxtLink>
|
||||
{{ t('Need help?') }}
|
||||
<NuxtLink to="https://docs.rustfs.com" class="text-blue-600 hover:underline">{{
|
||||
t('View Documentation')
|
||||
}}</NuxtLink>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -164,4 +185,4 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user