+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('addOauth2') }}
+
+
+
+
+
+ {{ t("tip") }}
+
+
+
+ {{ t('addOauth2') }}
+
+
+ {{ t('save') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('enable') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/views/user/UserLogin.vue b/frontend/src/views/user/UserLogin.vue
index 70d9a5f0..da4f5bdb 100644
--- a/frontend/src/views/user/UserLogin.vue
+++ b/frontend/src/views/user/UserLogin.vue
@@ -2,6 +2,7 @@
import { useMessage } from 'naive-ui'
import { onMounted, ref } from "vue";
import { useI18n } from 'vue-i18n'
+import { KeyFilled } from '@vicons/material'
import { api } from '../../api';
import { useGlobalState } from '../../store'
@@ -10,7 +11,10 @@ import { startAuthentication } from '@simplewebauthn/browser';
import Turnstile from '../../components/Turnstile.vue';
-const { userJwt, userOpenSettings, openSettings } = useGlobalState()
+const {
+ userJwt, userOpenSettings, openSettings,
+ userOauth2SessionState, userOauth2SessionClientID
+} = useGlobalState()
const message = useMessage();
const { t } = useI18n({
@@ -33,6 +37,7 @@ const { t } = useI18n({
pleaseCompleteTurnstile: 'Please complete turnstile',
pleaseLogin: 'Please login',
loginWithPasskey: 'Login with Passkey',
+ loginWith: 'Login with {provider}',
},
zh: {
login: '登录',
@@ -52,6 +57,7 @@ const { t } = useI18n({
pleaseCompleteTurnstile: '请完成人机验证',
pleaseLogin: '请登录',
loginWithPasskey: '使用 Passkey 登录',
+ loginWith: '使用 {provider} 登录',
}
}
});
@@ -184,6 +190,18 @@ const passkeyLogin = async () => {
}
};
+const oauth2Login = async (clientID) => {
+ try {
+ userOauth2SessionClientID.value = clientID;
+ userOauth2SessionState.value = Math.random().toString(36).substring(2);
+ const res = await api.fetch(`/user_api/oauth2/login_url?clientID=${clientID}&state=${userOauth2SessionState.value}`);
+ // redirect to oauth2 login page
+ location.href = res.url;
+ } catch (error) {
+ message.error(error.message || "login failed");
+ }
+};
+
onMounted(async () => {
});
@@ -208,8 +226,15 @@ onMounted(async () => {