107 lines
3.6 KiB
JavaScript
107 lines
3.6 KiB
JavaScript
/**
|
||
* 登录并保存会话,供页面渲染验证脚本复用。
|
||
*
|
||
* 为什么不 stub 接口:MEDISIGN 后端对无效 token 返回 401,
|
||
* utils/request.ts 的响应拦截器收到 401 会 clearAuthStorage() + 跳登录页,
|
||
* 伪造会话很容易被踢出去。走真实登录最省事。
|
||
*
|
||
* 验证码是强制的(不传会报「验证码错误或已过期」)。用法:
|
||
*
|
||
* node scripts/login.cjs # 第一步:抓验证码图片
|
||
* (用看图工具认出图片里的数字)
|
||
* node scripts/login.cjs 5274 # 第二步:带验证码登录,写 .session.json
|
||
*
|
||
* 结果写到 scripts/.session.json(已在 .gitignore 里,不会提交 token)。
|
||
*
|
||
* 文件用 .cjs 后缀:package.json 里的 "type": "module" 会把 .js 当 ES 模块,
|
||
* 而这里用 require 更简单,所以显式声明成 CommonJS。
|
||
*
|
||
* 依赖:Node 18+(内置 fetch)。无需额外安装依赖。
|
||
*/
|
||
const fs = require('fs')
|
||
const path = require('path')
|
||
|
||
const BASE_URL = process.env.VERIFY_BASE_URL || 'http://127.0.0.1:5173'
|
||
const USERNAME = process.env.VERIFY_USERNAME || 'admin'
|
||
const PASSWORD = process.env.VERIFY_PASSWORD || 'admin'
|
||
|
||
const OUT_DIR = __dirname
|
||
const CAPTCHA_JSON = path.join(OUT_DIR, '.captcha.json')
|
||
const CAPTCHA_PNG = path.join(OUT_DIR, '.captcha.png')
|
||
const SESSION_FILE = path.join(OUT_DIR, '.session.json')
|
||
|
||
async function fetchCaptcha() {
|
||
const res = await fetch(`${BASE_URL}/api/v1/auth/captcha`)
|
||
const json = await res.json()
|
||
|
||
if (json.code !== '0' && json.code !== 0) {
|
||
throw new Error('获取验证码失败: ' + json.message)
|
||
}
|
||
|
||
const { captchaId, imageBase64 } = json.data
|
||
fs.writeFileSync(CAPTCHA_JSON, JSON.stringify(json))
|
||
fs.writeFileSync(
|
||
CAPTCHA_PNG,
|
||
Buffer.from(String(imageBase64).replace(/^data:image\/\w+;base64,/, ''), 'base64'),
|
||
)
|
||
|
||
console.log('验证码已保存,请打开图片认出里面的数字:')
|
||
console.log(' ' + CAPTCHA_PNG)
|
||
console.log('captchaId = ' + captchaId)
|
||
console.log('')
|
||
console.log('然后执行: node scripts/login.cjs <识别出的数字>')
|
||
}
|
||
|
||
async function login(captchaCode) {
|
||
if (!fs.existsSync(CAPTCHA_JSON)) {
|
||
throw new Error('没有找到验证码,请先执行 node scripts/login.cjs 抓取验证码')
|
||
}
|
||
|
||
const { data } = JSON.parse(fs.readFileSync(CAPTCHA_JSON, 'utf8'))
|
||
|
||
const res = await fetch(`${BASE_URL}/api/v1/auth/login`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
username: USERNAME,
|
||
password: PASSWORD,
|
||
captchaId: data.captchaId,
|
||
captchaCode,
|
||
}),
|
||
})
|
||
const json = await res.json()
|
||
|
||
if (json.code !== '0' && json.code !== 0) {
|
||
throw new Error(
|
||
'登录失败: ' + json.message + '(验证码可能已过期,重新执行 node scripts/login.cjs)',
|
||
)
|
||
}
|
||
|
||
fs.writeFileSync(SESSION_FILE, JSON.stringify(json.data, null, 2))
|
||
|
||
console.log('登录成功')
|
||
console.log(
|
||
' 用户 = ' + json.data.user.displayName + ' (' + json.data.user.username + ')',
|
||
)
|
||
console.log(' campusId = ' + json.data.user.campusId)
|
||
// 登录响应里 dataScope / permissions 可能缺失:权限以 /v1/authorization/me 为准。
|
||
console.log(' dataScope = ' + (json.data.user.dataScope ?? '(未返回)'))
|
||
console.log(' permissions = ' + (json.data.user.permissions?.length ?? 0) + ' 项')
|
||
console.log(' 会话已写入 ' + SESSION_FILE)
|
||
}
|
||
|
||
async function main() {
|
||
const captchaCode = process.argv[2]
|
||
|
||
if (captchaCode) {
|
||
await login(captchaCode.trim())
|
||
} else {
|
||
await fetchCaptcha()
|
||
}
|
||
}
|
||
|
||
main().catch((err) => {
|
||
console.error(err.message)
|
||
process.exit(1)
|
||
})
|