feat: add login for plugin
This commit is contained in:
@@ -12,8 +12,10 @@ export const createCookie = (token: any, ctx: any) => {
|
||||
if (!domain) {
|
||||
return;
|
||||
}
|
||||
if (ctx.res.cookie) {
|
||||
ctx.res.cookie('token', token.token, {
|
||||
const browser = ctx.req.headers['user-agent'];
|
||||
const isBrowser = browser.includes('Mozilla'); // 浏览器
|
||||
if (isBrowser && ctx.res.cookie) {
|
||||
ctx.res.cookie('token', token.accessToken || token?.token, {
|
||||
maxAge: 7 * 24 * 60 * 60 * 1000, // 过期时间, 设置7天
|
||||
domain,
|
||||
sameSite: 'lax',
|
||||
@@ -21,7 +23,48 @@ export const createCookie = (token: any, ctx: any) => {
|
||||
});
|
||||
}
|
||||
};
|
||||
const clearCookie = (ctx: any) => {
|
||||
export type ReqHeaders = {
|
||||
host: string;
|
||||
'x-forwarded-for': string;
|
||||
'x-real-ip': string;
|
||||
'sec-ch-ua': string; // 浏览器
|
||||
'sec-ch-ua-mobile': string; // 移动设备
|
||||
'sec-ch-ua-platform': string; // 平台
|
||||
'sec-ch-ua-arch': string; // 架构
|
||||
'sec-ch-ua-bitness': string; // 位数
|
||||
'sec-ch-ua-full-version': string; // 完整版本
|
||||
'sec-ch-ua-full-version-list': string; // 完整版本列表
|
||||
'sec-fetch-dest': string; // 目标
|
||||
'sec-fetch-mode': string; // 模式
|
||||
'sec-fetch-site': string; // 站点
|
||||
'sec-fetch-user': string; // 用户
|
||||
'upgrade-insecure-requests': string; // 升级不安全请求
|
||||
'user-agent': string; // 用户代理
|
||||
accept: string; // 接受
|
||||
'accept-language': string; // 接受语言
|
||||
'accept-encoding': string; // 接受编码
|
||||
'cache-control': string; // 缓存控制
|
||||
pragma: string; // 预先
|
||||
expires: string; // 过期
|
||||
connection: string; // 连接
|
||||
cookie: string; // 饼干
|
||||
};
|
||||
export const getSomeInfoFromReq = (ctx: any) => {
|
||||
const headers = ctx.req.headers as ReqHeaders;
|
||||
const userAgent = headers['user-agent'];
|
||||
const host = headers['host'];
|
||||
const ip = headers['x-forwarded-for'] || ctx.req.connection.remoteAddress;
|
||||
console.log('req headers', headers);
|
||||
return {
|
||||
'user-agent': userAgent,
|
||||
browser: userAgent,
|
||||
isBrowser: userAgent.includes('Mozilla'),
|
||||
host,
|
||||
ip,
|
||||
headers,
|
||||
};
|
||||
};
|
||||
export const clearCookie = (ctx: any) => {
|
||||
if (!domain) {
|
||||
return;
|
||||
}
|
||||
@@ -87,7 +130,12 @@ app
|
||||
ctx.throw(500, 'Password error');
|
||||
}
|
||||
user.expireOrgs();
|
||||
const token = await user.createToken(null, loginType);
|
||||
const someInfo = getSomeInfoFromReq(ctx);
|
||||
const token = await user.createToken(null, loginType, {
|
||||
ip: someInfo.ip,
|
||||
browser: someInfo['user-agent'],
|
||||
host: someInfo.host,
|
||||
});
|
||||
createCookie(token, ctx);
|
||||
ctx.body = token;
|
||||
})
|
||||
|
||||
@@ -1,30 +1,72 @@
|
||||
import { app } from '@/app.ts';
|
||||
import { User } from '@/models/user.ts';
|
||||
import MD5 from 'crypto-js/md5.js';
|
||||
|
||||
import { authCan } from '@kevisual/code-center-module/models';
|
||||
import jsonwebtoken from 'jsonwebtoken';
|
||||
|
||||
// const tokenData: Record<string, string> = {};
|
||||
import { redis } from '@/app.ts';
|
||||
import { createCookie } from './me.ts';
|
||||
import { createCookie, clearCookie } from './me.ts';
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'user',
|
||||
key: 'webLogin',
|
||||
middleware: ['auth'],
|
||||
middleware: [authCan],
|
||||
})
|
||||
.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 `
|
||||
<html lang="zh-CN">
|
||||
<body>
|
||||
<h1>login with web page</h1>
|
||||
<a href="${reqUrl}">${reqUrl}</a>
|
||||
<script>
|
||||
const redirect = new URL('${reqUrl}', window.location.origin);
|
||||
const encodeRedirect = encodeURIComponent(redirect.toString());
|
||||
const toPage = new URL('/user/login/?user-check=true&redirect='+encodeRedirect, window.location.origin);
|
||||
setTimeout(() => {
|
||||
window.location.href = toPage.toString();
|
||||
}, 1000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
};
|
||||
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 (!sign) {
|
||||
await setErrorLoginTokenRedis(loginToken);
|
||||
ctx.throw(400, 'sign is required');
|
||||
}
|
||||
|
||||
if (!randomId) {
|
||||
await setErrorLoginTokenRedis(loginToken);
|
||||
ctx.throw(400, 'randomId is required');
|
||||
}
|
||||
const tokenSecret = 'xiao' + randomId;
|
||||
@@ -32,16 +74,19 @@ app
|
||||
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, 'plugin', { loginWith: 'cli' });
|
||||
@@ -63,11 +108,16 @@ app
|
||||
// const data = tokenData[loginToken];
|
||||
const data = await redis.get(loginToken);
|
||||
if (data) {
|
||||
ctx.body = JSON.parse(data);
|
||||
await redis.expire(loginToken, 3600);
|
||||
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');
|
||||
}
|
||||
createCookie(data, ctx);
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
Reference in New Issue
Block a user