enhance: 2FA is no longer required for the first 3min of login

This commit is contained in:
Jacky 2024-07-29 11:00:54 +08:00
parent 53c57b2d3d
commit 83981349d7
No known key found for this signature in database
GPG key ID: 215C21B10DF38B4D
6 changed files with 28 additions and 15 deletions

View file

@ -32,10 +32,11 @@ const (
) )
type LoginResponse struct { type LoginResponse struct {
Message string `json:"message"` Message string `json:"message"`
Error string `json:"error,omitempty"` Error string `json:"error,omitempty"`
Code int `json:"code"` Code int `json:"code"`
Token string `json:"token,omitempty"` Token string `json:"token,omitempty"`
SecureSessionID string `json:"secure_session_id,omitempty"`
} }
func Login(c *gin.Context) { func Login(c *gin.Context) {
@ -86,6 +87,8 @@ func Login(c *gin.Context) {
} }
// Check if the user enables 2FA // Check if the user enables 2FA
var secureSessionID string
if u.EnabledOTP() { if u.EnabledOTP() {
if json.OTP == "" && json.RecoveryCode == "" { if json.OTP == "" && json.RecoveryCode == "" {
c.JSON(http.StatusOK, LoginResponse{ c.JSON(http.StatusOK, LoginResponse{
@ -104,6 +107,8 @@ func Login(c *gin.Context) {
user.BanIP(clientIP) user.BanIP(clientIP)
return return
} }
secureSessionID = user.SetSecureSessionID(u.ID)
} }
// login success, clear banned record // login success, clear banned record
@ -119,9 +124,10 @@ func Login(c *gin.Context) {
} }
c.JSON(http.StatusOK, LoginResponse{ c.JSON(http.StatusOK, LoginResponse{
Code: LoginSuccess, Code: LoginSuccess,
Message: "ok", Message: "ok",
Token: token, Token: token,
SecureSessionID: secureSessionID,
}) })
} }

View file

@ -7,6 +7,8 @@ export interface AuthResponse {
message: string message: string
token: string token: string
code: number code: number
error: string
secure_session_id: string
} }
const auth = { const auth = {

View file

@ -16,7 +16,7 @@ function ws(url: string, reconnect: boolean = true): ReconnectingWebSocket | Web
url, `?token=${btoa(token.value)}`, node_id) url, `?token=${btoa(token.value)}`, node_id)
if (reconnect) if (reconnect)
return new ReconnectingWebSocket(_url) return new ReconnectingWebSocket(_url, undefined, { maxRetries: 10 })
return new WebSocket(_url) return new WebSocket(_url)
} }

View file

@ -1 +1 @@
{"version":"2.0.0-beta.29","build_id":151,"total_build":355} {"version":"2.0.0-beta.29","build_id":152,"total_build":356}

View file

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { LockOutlined, UserOutlined } from '@ant-design/icons-vue' import { LockOutlined, UserOutlined } from '@ant-design/icons-vue'
import { Form, message } from 'ant-design-vue' import { Form, message } from 'ant-design-vue'
import { useCookies } from '@vueuse/integrations/useCookies'
import { useUserStore } from '@/pinia' import { useUserStore } from '@/pinia'
import auth from '@/api/auth' import auth from '@/api/auth'
import install from '@/api/install' import install from '@/api/install'
@ -46,7 +47,9 @@ const rulesRef = reactive({
}) })
const { validate, validateInfos, clearValidate } = Form.useForm(modelRef, rulesRef) const { validate, validateInfos, clearValidate } = Form.useForm(modelRef, rulesRef)
const { login } = useUserStore() const userStore = useUserStore()
const { login } = userStore
const { secureSessionId } = storeToRefs(userStore)
const onSubmit = () => { const onSubmit = () => {
validate().then(async () => { validate().then(async () => {
@ -54,11 +57,13 @@ const onSubmit = () => {
await auth.login(modelRef.username, modelRef.password, passcode.value, recoveryCode.value).then(async r => { await auth.login(modelRef.username, modelRef.password, passcode.value, recoveryCode.value).then(async r => {
const next = (route.query?.next || '').toString() || '/' const next = (route.query?.next || '').toString() || '/'
const cookies = useCookies(['nginx-ui-2fa'])
switch (r.code) { switch (r.code) {
case 200: case 200:
message.success($gettext('Login successful'), 1) message.success($gettext('Login successful'), 1)
login(r.token) login(r.token)
secureSessionId.value = r.secure_session_id
cookies.set('secure_session_id', r.secure_session_id, { maxAge: 60 * 3 })
await router.push(next) await router.push(next)
break break
case 199: case 199:

View file

@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import GithubButton from 'vue-github-button' import GithubButton from 'vue-github-button'
import logo from '@/assets/img/logo.png' import logo from '@/assets/img/logo.png'
import version from '@/version.json' import ver from '@/version.json'
const this_year = new Date().getFullYear() const thisYear = new Date().getFullYear()
</script> </script>
<template> <template>
@ -19,7 +19,7 @@ const this_year = new Date().getFullYear()
</div> </div>
<h2>Nginx UI</h2> <h2>Nginx UI</h2>
<p>Yet another WebUI for Nginx</p> <p>Yet another WebUI for Nginx</p>
<p>Version: {{ version.version }} ({{ version.build_id || $gettext('Development Mode') }})</p> <p>Version: {{ ver.version }} ({{ ver.build_id || $gettext('Development Mode') }})</p>
<div class="star-on-github"> <div class="star-on-github">
<GithubButton <GithubButton
href="https://github.com/0xJacky/nginx-ui" href="https://github.com/0xJacky/nginx-ui"
@ -47,7 +47,7 @@ const this_year = new Date().getFullYear()
{{ $gettext('License') }} {{ $gettext('License') }}
</h3> </h3>
<p>GNU General Public License v3.0</p> <p>GNU General Public License v3.0</p>
<p>Copyright © 2021 - {{ this_year }} Nginx UI Team</p> <p>Copyright © 2021 - {{ thisYear }} Nginx UI Team</p>
</ACard> </ACard>
</template> </template>