Server: - Add Express framework, replace custom router/request parser - Create DAO layer (12 files) centralizing all 73 SQL queries - Rewrite 7 route files as thin Express controllers calling DAOs - Add SCF-to-Express adapter (lib/serverless.js) - Add auth middleware (middleware/auth.js) - Remove dead code from lib/auth.js Admin console: - Extract DataTable component (table + pagination) - Extract ConfirmModal component (modal + form styles) - Create listMixin for paginated list pages - Move form styles to common.css for slot compatibility - Refactor device + subscription pages as examples Miniprogram: - Split 734-line BLE monolith into 4 focused modules (protocol, connection, commands, barrel index) - Create API module (utils/api.js) with named functions - Create page utilities (utils/page.js) - Refactor index + profile pages to use API module
76 行
2.5 KiB
JavaScript
76 行
2.5 KiB
JavaScript
const jwt = require('jsonwebtoken')
|
|
const router = require('express').Router()
|
|
const { ok, fail } = require('../lib/response')
|
|
const { signUser, readBearer } = require('../lib/auth')
|
|
const { code2Session } = require('../lib/wechat')
|
|
const config = require('../config')
|
|
const userDao = require('../dao/user.dao')
|
|
const logDao = require('../dao/log.dao')
|
|
|
|
const wrap = fn => (req, res, next) => fn(req, res, next).catch(next)
|
|
|
|
router.post('/auth/login', wrap(async (req, res) => {
|
|
const session = await code2Session(req.body.code || '')
|
|
let user = await userDao.findByOpenid(session.openid)
|
|
if (!user) {
|
|
const result = await userDao.create(session.openid)
|
|
user = await userDao.findById(result.insertId)
|
|
await logDao.write({ user_id: user.user_id, action: 'user_register', detail: '新用户注册', ip: req.ip })
|
|
}
|
|
const token = signUser(user)
|
|
await logDao.write({ user_id: user.user_id, action: 'user_login', detail: '用户登录', ip: req.ip })
|
|
res.json(ok({
|
|
token,
|
|
user_id: String(user.user_id),
|
|
user_info: {
|
|
user_id: String(user.user_id),
|
|
nickname: user.nickname || '用户' + String(user.user_id),
|
|
avatar: user.avatar || '',
|
|
phone: user.phone || '',
|
|
gender: user.gender || 0
|
|
},
|
|
expires_in: 604800
|
|
}))
|
|
}))
|
|
|
|
router.post('/auth/refresh', wrap(async (req, res) => {
|
|
const token = readBearer(req.headers)
|
|
if (!token) return res.json(fail(1001, 'token_expired'))
|
|
|
|
let payload
|
|
try {
|
|
payload = jwt.verify(token, config.jwt.secret)
|
|
} catch (err) {
|
|
if (err.name === 'TokenExpiredError') {
|
|
try {
|
|
payload = jwt.verify(token, config.jwt.secret, { ignoreExpiration: true })
|
|
} catch (_) {
|
|
return res.json(fail(1001, 'token_expired'))
|
|
}
|
|
const now = Math.floor(Date.now() / 1000)
|
|
const gracePeriod = 3 * 24 * 60 * 60
|
|
if (now - payload.exp > gracePeriod) {
|
|
return res.json(fail(1001, 'token_expired'))
|
|
}
|
|
} else {
|
|
return res.json(fail(1001, 'token_expired'))
|
|
}
|
|
}
|
|
|
|
if (payload.type !== 'user') return res.json(fail(1001, 'token_expired'))
|
|
|
|
const now = Math.floor(Date.now() / 1000)
|
|
const sevenDays = 7 * 24 * 60 * 60
|
|
if (payload.exp && payload.exp > now && (payload.exp - now) > sevenDays) {
|
|
return res.json(ok({ token, expires_in: payload.exp - now }))
|
|
}
|
|
|
|
const user = await userDao.findById(payload.user_id)
|
|
if (!user) return res.json(fail(1001, 'token_expired'))
|
|
|
|
const newToken = signUser(user)
|
|
res.json(ok({ token: newToken, expires_in: 604800 }))
|
|
}))
|
|
|
|
module.exports = router
|