import { app } from '@/app.ts'; import { User } from '@/models/user.ts'; import MD5 from 'crypto-js/md5.js'; import { authCan } from '@/auth/index.ts'; import jsonwebtoken from 'jsonwebtoken'; import { redis } from '@/app.ts'; import { createCookie, clearCookie } from './me.ts'; import z from 'zod'; app .route({ path: 'user', key: 'webLogin', description: 'web登录接口,配合插件使用', middleware: [authCan], metadata: { args: { loginToken: z.string().describe('web登录令牌,服务端生成,客户端保持一致'), sign: z.string().describe('签名,服务端生成,客户端保持一致'), randomId: z.string().describe('随机字符串,服务端和客户端保持一致'), } } }) .define(async (ctx) => { const tokenUser = ctx.state.tokenUser; const token = ctx.query.token; const { loginToken, sign, randomId } = ctx.query || {}; const setErrorLoginTokenRedis = async (loginToken: string) => { await redis.set(loginToken, JSON.stringify({}), 'EX', 2 * 60); // 2分钟 }; if (!tokenUser) { if (token) { console.log('web-login, token', ' run clearCookie', token, tokenUser); // clearCookie(ctx); } else { // const message = 'token is expired, please login in web page. '; } try { ctx.res.setHeader('Content-Type', 'text/html'); const createRedirectHtml = () => { const reqUrl = ctx.req.url; return `

login with web page

${reqUrl} `; }; ctx.res.end(createRedirectHtml()); } catch (e) { await setErrorLoginTokenRedis(loginToken); ctx.throw(400, 'token is expired and redirect error'); } return; } if (!loginToken) { await setErrorLoginTokenRedis(loginToken); ctx.throw(400, 'loginToken is required'); } if (!randomId) { await setErrorLoginTokenRedis(loginToken); ctx.throw(400, 'randomId is required'); } const tokenSecret = 'xiao' + randomId; if (sign) { let payload: any = {}; try { payload = jsonwebtoken.verify(loginToken, tokenSecret); } catch (e) { await setErrorLoginTokenRedis(loginToken); ctx.throw(400, 'loginToken error'); } const { timestamp } = payload; const checkSign = MD5(`${tokenSecret}${timestamp}`).toString(); if (sign !== checkSign) { await setErrorLoginTokenRedis(loginToken); ctx.throw(400, 'sign error'); } } const user = await User.findByPk(tokenUser.id); if (!user) { await setErrorLoginTokenRedis(loginToken); ctx.throw(400, 'user not found'); } const data = await user.createToken(null, 'jwks', { loginWith: 'cli' }); await redis.set(loginToken, JSON.stringify(data), 'EX', 10 * 60); // 10分钟 ctx.body = 'success'; }) .addTo(app); app .route({ path: 'user', key: 'checkLoginStatus', description: '循环检查登陆状态', }) .define(async (ctx) => { const { loginToken } = ctx.query; if (!loginToken) { ctx.throw(400, 'loginToken is required'); } // const data = tokenData[loginToken]; const data = await redis.get(loginToken); if (data) { const token = JSON.parse(data); if (token.accessToken) { ctx.body = token; createCookie(token, ctx); } else { ctx.throw(500, 'Checked error Failed, login failed, please login again'); } await redis.expire(loginToken, 2 * 60); // 2分钟 } else { ctx.throw(400, 'Checked Failed'); } }) .addTo(app);