const Base = require('../base'); const svgCaptcha = require('svg-captcha'); module.exports = class extends Base { // 登录页面 async loginAction() { // 已登录状态访问登录页,自动退出 if (this.cookie('admin_token')) { this.cookie('admin_token', null); } this.assign('siteConfig', {}); this.assign('now_year', new Date().getFullYear()); return this.display(); } // 图形验证码 async captchaAction() { const captcha = svgCaptcha.create({ size: 4, ignoreChars: '0oO1lIi', noise: 3, color: true, background: '#f0f2f5', width: 120, height: 40 }); // 存入session await this.session('captcha', captcha.text.toLowerCase()); this.ctx.type = 'image/svg+xml'; this.ctx.body = captcha.data; } // 登录接口 async doLoginAction() { const { username, password, remember, captcha } = this.post(); if (!username || !password) { return this.fail('请输入用户名和密码'); } // 验证码校验 if (!captcha) { return this.fail('请输入验证码'); } const sessionCaptcha = await this.session('captcha'); // 用完即清 await this.session('captcha', null); if (!sessionCaptcha || captcha.toLowerCase() !== sessionCaptcha) { return this.fail('验证码错误'); } // 查找用户(不限status,锁定判断在后面) const user = await this.model('admin_user') .where({ username, is_deleted: 0 }) .find(); if (think.isEmpty(user)) { return this.fail('用户名或密码错误'); } // 账号停用 if (user.status !== 1) { return this.fail('账号已被禁用,请联系管理员'); } // 锁定判断:当日错误>=5次 const today = new Date().toISOString().slice(0, 10); const failDate = user.login_fail_date ? new Date(user.login_fail_date).toISOString().slice(0, 10) : null; const failCount = (failDate === today) ? (user.login_fail_count || 0) : 0; if (failCount >= 5) { return this.fail('密码错误次数过多,账号已锁定,请联系管理员或次日自动解锁'); } // 密码验证 if (user.password !== think.md5(password)) { const newCount = failCount + 1; await this.model('admin_user').where({ id: user.id }).update({ login_fail_count: newCount, login_fail_date: today }); const remain = 5 - newCount; if (remain <= 0) { return this.fail('密码错误次数过多,账号已锁定,请联系管理员或次日自动解锁'); } return this.fail(`密码错误,还剩${remain}次机会`); } // 登录成功,清除错误计数,更新登录信息 await this.model('admin_user').where({ id: user.id }).update({ login_fail_count: 0, login_fail_date: null, last_login_time: think.datetime(), last_login_ip: this.ctx.ip || '' }); // 生成JWT Token const token = Base.generateToken({ id: user.id, username: user.username, role_id: user.role_id }); const cookieOpts = { httpOnly: true, path: '/' }; if (remember) { cookieOpts.maxAge = Base.JWT_EXPIRES_IN * 1000; } this.cookie('admin_token', token, cookieOpts); this.adminUser = { id: user.id, username: user.username }; await this.log('login', '系统', `${user.username} 登录系统`); return this.success({ token }); } // 退出登录 async logoutAction() { if (this.adminUser) { await this.log('logout', '系统', `${this.adminUser.username} 退出系统`); } this.cookie('admin_token', null); return this.redirect('/admin/login.html'); } };