remove mark
This commit is contained in:
261
src/auth/models/user-secret.ts
Normal file
261
src/auth/models/user-secret.ts
Normal file
@@ -0,0 +1,261 @@
|
||||
import { DataTypes, Model, Sequelize } from 'sequelize';
|
||||
|
||||
import { useContextKey } from '@kevisual/context';
|
||||
import { Redis } from 'ioredis';
|
||||
import { SyncOpts, User } from './user.ts';
|
||||
import { oauth } from '../oauth/auth.ts';
|
||||
import { OauthUser } from '../oauth/oauth.ts';
|
||||
export const redis = useContextKey<Redis>('redis');
|
||||
|
||||
const UserSecretStatus = ['active', 'inactive', 'expired'] as const;
|
||||
|
||||
type Data = {
|
||||
[key: string]: any;
|
||||
/**
|
||||
* 微信开放平台的某一个应用的openid
|
||||
*/
|
||||
wxOpenid?: string;
|
||||
/**
|
||||
* 微信开放平台的unionid:主要
|
||||
*/
|
||||
wxUnionid?: string;
|
||||
/**
|
||||
* 微信公众号的openid:次要
|
||||
*/
|
||||
wxmpOpenid?: string;
|
||||
|
||||
}
|
||||
export class UserSecret extends Model {
|
||||
static oauth = oauth;
|
||||
declare id: string;
|
||||
declare token: string;
|
||||
declare userId: string;
|
||||
declare orgId: string;
|
||||
declare title: string;
|
||||
declare description: string;
|
||||
declare status: (typeof UserSecretStatus)[number];
|
||||
declare expiredTime: Date;
|
||||
declare data: Data;
|
||||
/**
|
||||
* 验证token
|
||||
* @param token
|
||||
* @returns
|
||||
*/
|
||||
static async verifyToken(token: string) {
|
||||
if (!oauth.isSecretKey(token)) {
|
||||
return await oauth.verifyToken(token);
|
||||
}
|
||||
// const secretToken = await oauth.verifyToken(token);
|
||||
// if (secretToken) {
|
||||
// return secretToken;
|
||||
// }
|
||||
const userSecret = await UserSecret.findOne({
|
||||
where: { token },
|
||||
});
|
||||
if (!userSecret) {
|
||||
return null; // 如果没有找到对应的用户密钥,则返回null
|
||||
}
|
||||
if (userSecret.isExpired()) {
|
||||
return null; // 如果用户密钥已过期,则返回null
|
||||
}
|
||||
if (userSecret.status !== 'active') {
|
||||
return null; // 如果用户密钥状态不是active,则返回null
|
||||
}
|
||||
// 如果用户密钥未过期,则返回用户信息
|
||||
const oauthUser = await userSecret.getOauthUser();
|
||||
if (!oauthUser) {
|
||||
return null; // 如果没有找到对应的oauth用户,则返回null
|
||||
}
|
||||
// await oauth.saveSecretKey(oauthUser, userSecret.token);
|
||||
// 存储到oauth中的token store中
|
||||
return oauthUser;
|
||||
}
|
||||
/**
|
||||
* owner 组织用户的 oauthUser
|
||||
* @returns
|
||||
*/
|
||||
async getOauthUser() {
|
||||
const user = await User.findOne({
|
||||
where: { id: this.userId },
|
||||
attributes: ['id', 'username', 'type', 'owner'],
|
||||
});
|
||||
let org: User = null;
|
||||
if (!user) {
|
||||
return null; // 如果没有找到对应的用户,则返回null
|
||||
}
|
||||
const expiredTime = this.expiredTime ? new Date(this.expiredTime).getTime() : null;
|
||||
const oauthUser: Partial<OauthUser> = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
type: 'user',
|
||||
oauthExpand: {
|
||||
expiredTime: expiredTime,
|
||||
},
|
||||
};
|
||||
if (this.orgId) {
|
||||
org = await User.findOne({
|
||||
where: { id: this.orgId },
|
||||
attributes: ['id', 'username', 'type', 'owner'],
|
||||
});
|
||||
if (org) {
|
||||
oauthUser.id = org.id;
|
||||
oauthUser.username = org.username;
|
||||
oauthUser.type = 'org';
|
||||
oauthUser.uid = user.id;
|
||||
} else {
|
||||
console.warn(`getOauthUser: org not found for orgId ${this.orgId}`);
|
||||
}
|
||||
}
|
||||
|
||||
return oauth.getOauthUser(oauthUser);
|
||||
}
|
||||
isExpired() {
|
||||
if (!this.expiredTime) {
|
||||
return false; // 没有设置过期时间
|
||||
}
|
||||
const now = Date.now();
|
||||
const expiredTime = new Date(this.expiredTime);
|
||||
return now > expiredTime.getTime(); // 如果当前时间大于过期时间,则认为已过期
|
||||
}
|
||||
async createNewToken() {
|
||||
if (this.token) {
|
||||
await oauth.delToken(this.token);
|
||||
}
|
||||
const token = await UserSecret.createToken();
|
||||
this.token = token;
|
||||
await this.save();
|
||||
return token;
|
||||
}
|
||||
static async createToken() {
|
||||
let token = oauth.generateSecretKey();
|
||||
// 确保生成的token是唯一的
|
||||
while (await UserSecret.findOne({ where: { token } })) {
|
||||
token = oauth.generateSecretKey();
|
||||
}
|
||||
return token;
|
||||
}
|
||||
static async createSecret(tokenUser: { id: string; uid?: string }, expireDay = 365) {
|
||||
const expireTime = expireDay * 24 * 60 * 60 * 1000; // 转换为毫秒
|
||||
const token = await UserSecret.createToken();
|
||||
let userId = tokenUser.id;
|
||||
let orgId: string = null;
|
||||
if (tokenUser.uid) {
|
||||
userId = tokenUser.uid;
|
||||
orgId = tokenUser.id; // 如果是组织用户,则uid是组织ID
|
||||
}
|
||||
const userSecret = await UserSecret.create({
|
||||
userId,
|
||||
orgId,
|
||||
token,
|
||||
expiredTime: new Date(Date.now() + expireTime),
|
||||
});
|
||||
|
||||
return userSecret;
|
||||
}
|
||||
async getPermission(opts: { id: string; uid?: string }) {
|
||||
const { id, uid } = opts;
|
||||
let userId: string = id;
|
||||
let hasPermission = false;
|
||||
let isUser = false;
|
||||
let isAdmin: boolean = null;
|
||||
if (uid) {
|
||||
userId = uid;
|
||||
}
|
||||
if (!id) {
|
||||
return {
|
||||
hasPermission,
|
||||
isUser,
|
||||
isAdmin,
|
||||
};
|
||||
}
|
||||
if (this.userId === userId) {
|
||||
hasPermission = true;
|
||||
isUser = true;
|
||||
}
|
||||
|
||||
if (hasPermission) {
|
||||
return {
|
||||
hasPermission,
|
||||
isUser,
|
||||
isAdmin,
|
||||
};
|
||||
}
|
||||
if (this.orgId) {
|
||||
const orgUser = await User.findByPk(this.orgId);
|
||||
if (orgUser && orgUser.owner === userId) {
|
||||
isAdmin = true;
|
||||
hasPermission = true;
|
||||
}
|
||||
}
|
||||
return {
|
||||
hasPermission,
|
||||
isUser,
|
||||
isAdmin,
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 组织模型,在sequelize之后初始化
|
||||
*/
|
||||
export const UserSecretInit = async (newSequelize?: any, tableName?: string, sync?: SyncOpts) => {
|
||||
const sequelize = useContextKey<Sequelize>('sequelize');
|
||||
UserSecret.init(
|
||||
{
|
||||
id: {
|
||||
type: DataTypes.UUID,
|
||||
primaryKey: true,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
defaultValue: 'active',
|
||||
comment: '状态',
|
||||
},
|
||||
title: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
},
|
||||
expiredTime: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
token: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '用户密钥',
|
||||
defaultValue: '',
|
||||
},
|
||||
userId: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: true,
|
||||
},
|
||||
data: {
|
||||
type: DataTypes.JSONB,
|
||||
allowNull: true,
|
||||
defaultValue: {},
|
||||
},
|
||||
orgId: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: true,
|
||||
comment: '组织ID',
|
||||
},
|
||||
},
|
||||
{
|
||||
sequelize: newSequelize || sequelize,
|
||||
modelName: tableName || 'cf_user_secret',
|
||||
},
|
||||
);
|
||||
if (sync) {
|
||||
await UserSecret.sync({ alter: true, logging: false, ...sync }).catch((e) => {
|
||||
console.error('UserSecret sync', e);
|
||||
});
|
||||
return UserSecret;
|
||||
}
|
||||
return UserSecret;
|
||||
};
|
||||
export const UserSecretModel = useContextKey('UserSecretModel', () => UserSecret);
|
||||
Reference in New Issue
Block a user