diff --git a/internal/http/middleware/must_login.go b/internal/http/middleware/must_login.go index 3cdb3994..46093272 100644 --- a/internal/http/middleware/must_login.go +++ b/internal/http/middleware/must_login.go @@ -29,7 +29,8 @@ func MustLogin(t *gotext.Locale, session *sessions.Manager) func(next http.Handl "/api/user/key", "/api/user/login", "/api/user/logout", - "/api/user/isLogin", + "/api/user/is_login", + "/api/user/is_2fa", "/api/dashboard/panel", } return func(next http.Handler) http.Handler { diff --git a/internal/http/request/user.go b/internal/http/request/user.go index d2249c88..b2d0b317 100644 --- a/internal/http/request/user.go +++ b/internal/http/request/user.go @@ -12,7 +12,7 @@ type UserLogin struct { } type UserIsTwoFA struct { - Username string `uri:"username" validate:"required"` + Username string `query:"username" validate:"required"` } type UserCreate struct { diff --git a/internal/route/http.go b/internal/route/http.go index b492f386..973b60c4 100644 --- a/internal/route/http.go +++ b/internal/route/http.go @@ -111,6 +111,7 @@ func (route *Http) Register(r *chi.Mux) { r.With(middleware.Throttle(5, time.Minute)).Post("/login", route.user.Login) r.Post("/logout", route.user.Logout) r.Get("/is_login", route.user.IsLogin) + r.Get("/is_2fa", route.user.IsTwoFA) r.Get("/info", route.user.Info) }) diff --git a/web/src/api/panel/user/index.ts b/web/src/api/panel/user/index.ts index ad0a61c5..4038d2d0 100644 --- a/web/src/api/panel/user/index.ts +++ b/web/src/api/panel/user/index.ts @@ -4,16 +4,19 @@ export default { // 公钥 key: () => http.Get('/user/key'), // 登录 - login: (username: string, password: string, safe_login: boolean) => + login: (username: string, password: string, pass_code: string, safe_login: boolean) => http.Post('/user/login', { username, password, + pass_code, safe_login }), // 登出 logout: () => http.Post('/user/logout'), // 是否登录 isLogin: () => http.Get('/user/is_login'), + // 是否2FA + isTwoFA: (username: string) => http.Get('/user/is_2fa', { params: { username } }), // 获取用户信息 info: () => http.Get('/user/info'), // 获取用户列表 diff --git a/web/src/views/login/IndexView.vue b/web/src/views/login/IndexView.vue index ea4da3e5..a9764a29 100644 --- a/web/src/views/login/IndexView.vue +++ b/web/src/views/login/IndexView.vue @@ -19,12 +19,14 @@ interface LoginInfo { username: string password: string safe_login: boolean + pass_code: string } const loginInfo = ref({ username: '', password: '', - safe_login: true + safe_login: true, + pass_code: '' }) const localLoginInfo = getLocal('loginInfo') as LoginInfo @@ -37,11 +39,12 @@ const userStore = useUserStore() const themeStore = useThemeStore() const loging = ref(false) const isRemember = useStorage('isRemember', false) +const showTwoFA = ref(false) const logo = computed(() => themeStore.logo || logoImg) async function handleLogin() { - const { username, password, safe_login } = loginInfo.value + const { username, password, pass_code, safe_login } = loginInfo.value if (!username || !password) { window.$message.warning($gettext('Please enter username and password')) return @@ -56,6 +59,7 @@ async function handleLogin() { user.login( rsaEncrypt(username, String(unref(key))), rsaEncrypt(password, String(unref(key))), + pass_code, safe_login ) ).onSuccess(async () => { @@ -82,6 +86,20 @@ async function handleLogin() { loging.value = false } +const isTwoFA = () => { + const { username } = loginInfo.value + if (!username) { + return + } + useRequest(user.isTwoFA(username)) + .onSuccess(({ data }) => { + showTwoFA.value = Boolean(data) + }) + .onError(() => { + showTwoFA.value = false + }) +} + watch(isLogin, async () => { if (isLogin) { await addDynamicRoutes() @@ -113,6 +131,7 @@ watch(isLogin, async () => { autofocus class="h-50 items-center pl-10 text-16" :placeholder="$gettext('Username')" + :on-blur="isTwoFA" />
@@ -126,6 +145,16 @@ watch(isLogin, async () => { @keydown.enter="handleLogin" />
+
+ +