47 lines
1.8 KiB
JavaScript
47 lines
1.8 KiB
JavaScript
import crypto from 'crypto'
|
|
|
|
// ---------------- 令牌存储 ----------------
|
|
export const accessTokens = new Map() // token -> { userId, expireAt }
|
|
export const refreshTokens = new Map() // token -> { userId, expireAt }
|
|
|
|
export const ACCESS_TOKEN_TTL_MS = 30 * 60 * 1000
|
|
export const REFRESH_TOKEN_TTL_MS = 7 * 24 * 60 * 60 * 1000
|
|
|
|
export function genToken() {
|
|
return crypto.randomBytes(24).toString('hex')
|
|
}
|
|
|
|
export function issueTokenPair(userId) {
|
|
const accessToken = genToken()
|
|
const refreshToken = genToken()
|
|
accessTokens.set(accessToken, { userId, expireAt: Date.now() + ACCESS_TOKEN_TTL_MS })
|
|
refreshTokens.set(refreshToken, { userId, expireAt: Date.now() + REFRESH_TOKEN_TTL_MS })
|
|
return { accessToken, refreshToken }
|
|
}
|
|
|
|
// ---------------- 短信验证码 ----------------
|
|
// key: `${businessType}:${phone}`,value: { code, expireAt }
|
|
export const smsCodes = new Map()
|
|
export const SMS_CODE_TTL_MS = 5 * 60 * 1000
|
|
export const FIXED_SMS_CODE = '123456' // 万能码,与真实生成码同时有效,便于手动测试
|
|
|
|
export function genSmsCode(businessType, phone) {
|
|
const code = String(Math.floor(100000 + Math.random() * 900000))
|
|
smsCodes.set(`${businessType}:${phone}`, { code, expireAt: Date.now() + SMS_CODE_TTL_MS })
|
|
// eslint-disable-next-line no-console
|
|
console.log(`[mock-server] 短信验证码 businessType=${businessType} phone=${phone} code=${code}`)
|
|
return code
|
|
}
|
|
|
|
export function verifySmsCode(businessType, phone, inputCode) {
|
|
if (inputCode === FIXED_SMS_CODE) return true
|
|
const record = smsCodes.get(`${businessType}:${phone}`)
|
|
if (!record) return false
|
|
if (record.expireAt < Date.now()) return false
|
|
return record.code === inputCode
|
|
}
|
|
|
|
// ---------------- 登录失败次数(连续失败5次锁定) ----------------
|
|
export const loginFailCounts = new Map() // username -> count
|
|
export const MAX_LOGIN_FAIL = 5
|