我有使用 GraphQL 的 NodeJS Web 服务器,使用 2 个连接。一个具有管理员访问权限,另一个具有增删改查访问权限。
底层 Postgres DB 有行级安全策略,即:
ALTER TABLE main.user ENABLE ROW LEVEL SECURITY;
CREATE POLICY user_isolation_policy ON main.user USING (id = current_setting('app.current_user_id')::UUID);
在登录用户之前,我需要从数据库获取他们的 id
,然后在登录时在 Postgres session 中设置 current_user_id
变量。
但是,当我尝试取回用户时,我希望只取回登录的用户,而不是所有人 - 这就是使用 pgAdmin 的行为方式。但是,在这里我收到以下错误:
error: error: unrecognized configuration parameter "app.current_user_id"
以下是我如何登录用户:
@Resolver()
export class LoginResolver {
@Mutation(() => LoginResponse)
public async login(
@Arg('email') email: string,
@Arg('password') password: string,
@Ctx() { res }: AppContext
): Promise<LoginResponse> {
try {
// get user from the admin repo so we can get their ID
const userRepository = (await adminConnection).getRepository(User)
const user = await userRepository.findOne({ where: { email } })
if (!user) throw new Error('user not found')
// using the api repo (not admin), set the variable
User.getRepository().query(`SET app.current_user_id TO "${user.id}"`)
const isValid = await bcrypt.compare(password, user.password)
if (!isValid) throw new Error('incorrect password')
if (!user.isConfirmed) throw new Error('email not confirmed')
sendRefreshToken(res, user.createRefreshToken())
return { token: user.createAccessToken() }
} catch (error) {
throw new Error(error)
}
}
}
以下是我尝试找回用户的方法:
@Resolver()
export class UsersResolver {
@Authorized(UserRole.admin, UserRole.super)
@Query(() => [User])
public users(): Promise<User[]> {
return User.find()
}
}
请注意,如果我删除该策略,GraphQL 会正常运行,不会出现错误。
设置的变量不持久。如何在用户登录时保留变量?
最佳答案
这种方法对我有用:
import { EntityManager, getConnection, getConnectionManager, getManager } from "typeorm";
import { EventSubscriber, EntitySubscriberInterface, InsertEvent, UpdateEvent, RemoveEvent } from "typeorm";
@EventSubscriber()
export class CurrentUserSubscriber implements EntitySubscriberInterface {
// get the userId from the current http request/headers/wherever you store it (currently I'm typeorm only, not as part of nest/express app)
async setUserId(mng: EntityManager, userId: string) {
await mng.query(`SELECT set_config('app.current_user_id', '${userId}', true);`)
}
async beforeInsert(event: InsertEvent<any>) {
await this.setUserId(event.manager, 'myUserId');
}
async beforeUpdate(event: UpdateEvent<any>) {
await this.setUserId(event.manager, 'myUserId');
}
async beforeRemove(event: RemoveEvent<any>) {
await this.setUserId(event.manager, 'myUserId');
}
}
不要忘记在 ormconfig.js
中配置 subscribers
属性,例如:
"subscribers": [
"src/subscribers/CurrentUserSubscriber.ts",
],
关于postgresql - Postgres 使用 TypeORM SET 运行时变量,如何在调用之间的连接生命周期中保留变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65944175/