diff --git a/CHANGELOG.md b/CHANGELOG.md index cf03e39..e3fcb17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ -## [2.3.0](https://github.com/chaos-zhu/easynode/releases) (2024-10-xx) +## [2.3.0](https://github.com/chaos-zhu/easynode/releases) (2024-10-24) * 重构本地数据库存储方式(性能提升一个level~) -* 支持MFA2二次验证 +* 支持MFA2二次登录验证 * 优化了一些页面在移动端的展示 * 修复偶现刷新页面需重新登录的bug diff --git a/server/app/controller/user.js b/server/app/controller/user.js index 9219f51..efc8af7 100644 --- a/server/app/controller/user.js +++ b/server/app/controller/user.js @@ -24,7 +24,7 @@ let loginCountDown = forbidTimer let forbidLogin = false const login = async ({ res, request }) => { - let { body: { loginName, ciphertext, jwtExpires }, ip: clientIp } = request + let { body: { loginName, ciphertext, jwtExpires, mfa2Token }, ip: clientIp } = request if (!loginName && !ciphertext) return res.fail({ msg: '请求非法!' }) if (forbidLogin) return res.fail({ msg: `禁止登录! 倒计时[${ loginCountDown }s]后尝试登录或重启面板服务` }) loginErrCount++ @@ -55,10 +55,13 @@ const login = async ({ res, request }) => { // 登录流程 try { - // console.log('ciphertext', ciphertext) let loginPwd = await RSADecryptAsync(ciphertext) - // console.log('Decrypt解密password:', loginPwd) - let { user, pwd } = await keyDB.findOneAsync({}) + let { user, pwd, enableMFA2, secret } = await keyDB.findOneAsync({}) + if (enableMFA2) { + const isValid = speakeasy.totp.verify({ secret, encoding: 'base32', token: mfa2Token, window: 1 }) + console.log('MFA2 verfify:', isValid) + if (!isValid) return res.fail({ msg: '验证失败' }) + } if (loginName === user && loginPwd === 'admin' && pwd === 'admin') { const token = await beforeLoginHandler(clientIp, jwtExpires) return res.success({ data: { token, jwtExpires }, msg: '登录成功,请及时修改默认用户名和密码' }) @@ -68,8 +71,8 @@ const login = async ({ res, request }) => { const token = await beforeLoginHandler(clientIp, jwtExpires) return res.success({ data: { token, jwtExpires }, msg: '登录成功' }) } catch (error) { - console.log('解密失败:', error) - res.fail({ msg: '解密失败, 请查看服务端日志' }) + console.log('登录失败:', error.message) + res.fail({ msg: '登录失败, 请查看服务端日志' }) } } @@ -87,7 +90,7 @@ const beforeLoginHandler = async (clientIp, jwtExpires) => { const { ip, country, city } = clientIPInfo || {} consola.info('登录成功:', new Date(), { ip, country, city }) - // 邮件登录通知 + // 登录通知 sendNoticeAsync('login', '登录提醒', `地点:${ country + city }\nIP: ${ ip }`) await logDB.insertAsync({ ip, country, city, date: Date.now(), type: 'login' }) @@ -140,12 +143,7 @@ const enableMFA2 = async ({ res, request }) => { if (!token) return res.fail({ data: false, msg: '参数错误' }) try { // const isValid = authenticator.verify({ token, secret: tempSecret }) - const isValid = speakeasy.totp.verify({ - secret: tempSecret, - encoding: 'base32', - token, - window: 1 - }) + const isValid = speakeasy.totp.verify({ secret: tempSecret, encoding: 'base32', token, window: 1 }) if (!isValid) return res.fail({ msg: '验证失败' }) const keyConfig = await keyDB.findOneAsync({}) keyConfig.enableMFA2 = true diff --git a/server/app/utils/verify-auth.js b/server/app/utils/verify-auth.js index 0ad1cf1..c73d16d 100644 --- a/server/app/utils/verify-auth.js +++ b/server/app/utils/verify-auth.js @@ -10,7 +10,7 @@ const enumLoginCode = { ERROR_TOKEN: -2 } -// 校验token与登录IP +// 校验token const verifyAuthSync = async (token, clientIp) => { consola.info('verifyAuthSync IP:', clientIp) try { diff --git a/web/package.json b/web/package.json index 39a3b55..6993074 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "web", - "version": "2.2.8", + "version": "2.3.0", "description": "easynode-web", "private": true, "scripts": { diff --git a/web/src/views/login/index.vue b/web/src/views/login/index.vue index dacff51..d98d9d9 100644 --- a/web/src/views/login/index.vue +++ b/web/src/views/login/index.vue @@ -44,6 +44,17 @@ + + + 一次性会话 @@ -70,10 +81,7 @@