将'nestjs/jwt'签名与动态/与用户相关的秘密一起使用 [英] Using 'nestjs/jwt' signing with dynamic/user-related secret
问题描述
我正在尝试根据尝试登录的用户的机密信息创建用户令牌.但是,我不想使用环境中的机密信息,而是要使用分配给数据库内部用户对象的机密信息.
I'm trying to create a user token based on the secret of the user trying to log in. However instead of using a secret from the environment I want to use a secret assigned to a user object inside the database.
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { UserService } from '@src/modules/user/services';
@Injectable()
export class AuthService {
public constructor(private readonly jwtService: JwtService,
private readonly userService: UserService) {}
public async createToken(email: string): Promise<JwtReply> {
const expiresIn = 60 * 60 * 24;
const user = await this.userService.user({ where: { email } });
const accessToken = await this.jwtService.signAsync({ email: user.email },
/* user.secret ,*/
{ expiresIn });
return {
accessToken,
expiresIn,
};
}
}
我是Nestjs的新手,也许我错过了一些东西.
node-jsonwebtoken 确实在nestjs/jwt
缺少此参数(请参见代码).在不使用node-jsonwebtoken
或更抽象的问题的情况下,您将如何解决此问题:在这里,我处理用户机密的方式是否有意义?谢谢.
I'm new to Nestjs and maybe I'm missing something.
node-jsonwebtoken does provide the necessary parameter in the sign(...)
function. nestjs/jwt
is missing this parameter (see code). How would you solve it without using node-jsonwebtoken
or maybe a more abstract question: does my way of handling user secret make sense here? Thanks.
推荐答案
仅使用nest的JwtModule
还不可能,但是您可以自己轻松实现缺少的部分.
This is not yet possible solely with nest's JwtModule
but you can easily implement the missing parts yourself.
您可以通过调用以下路由来创建令牌:
You can create tokens by calling the following routes:
user1(密码:"123"): https://yw7wz99zv1.sse.codesandbox. io/login/1
user2(机密:"456"): https://yw7wz99zv1.sse.codesandbox.io/login/2
user1 (secret: '123'): https://yw7wz99zv1.sse.codesandbox.io/login/1
user2 (secret: '456'): https://yw7wz99zv1.sse.codesandbox.io/login/2
然后用您的令牌调用受保护的路由'/'
并接收您的用户:
Then call the protected route '/'
with your token and receive your user:
curl -X GET https://yw7wz99zv1.sse.codesandbox.io/ \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxIiwiaWF0IjoxNTUzNjQwMjc5fQ.E5o3djesqWVHNGe-Hi3KODp0aTiQU9X_H3Murht1R5U'
它如何工作?
在AuthService
中,我只是使用标准的jsonwebtoken
库来创建令牌.然后,您可以从登录路径致电createToken
:
How does it work?
In the AuthService
I'm just using the standard jsonwebtoken
library to create the token. You can then call createToken
from your login route:
import * as jwt from 'jsonwebtoken';
export class AuthService {
constructor(private readonly userService: UserService) {}
createToken(userId: string) {
const user = this.userService.getUser(userId);
return jwt.sign({ userId: user.userId }, user.secret, { expiresIn: 3600 });
}
// ...
}
在JwtStrategy
中,您可以使用secretOrKeyProvider
而不是secretOrKey
,它可以异步访问UserService
来动态获取用户密码:
In the JwtStrategy
you use secretOrKeyProvider
instead of secretOrKey
which can asynchronously access the UserService
to get the user secret dynamically:
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(
private readonly authService: AuthService,
private readonly userService: UserService,
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKeyProvider: (request, jwtToken, done) => {
const decodedToken: any = jwt.decode(jwtToken);
const user = this.userService.getUser(decodedToken.userId);
done(null, user.secret);
},
});
}
// ...
}
请注意,将不会使用传递给JwtModule
的选项,例如expiresIn
,而是直接将选项传递给AuthService
.导入JwtModule
时不带任何选项:
Note that the options you pass to the JwtModule
like expiresIn
will not be used, instead directly pass your options in the AuthService
. Import the JwtModule
without any options:
JwtModule.register({})
常规
我在这里处理用户秘密的方式有意义吗?
Does my way of handling user secret make sense here?
在不知道您的确切要求的情况下很难回答.我猜jwt有动态秘密的用例,但是随着它您将失去jwt的一个重要特性:它们是无状态的.这意味着您的AuthService
可以发出jwt令牌,而某些需要身份验证的ProductService
可以仅信任jwt(它知道秘密)而无需调用其他服务(即必须查询数据库的UserService
)
This is hard to answer without knowing your exact requirements. I guess there are use cases for jwt with dynamic secrets but with it you are losing a great property of jwt: they are stateless. This means that your AuthService
can issue a jwt token and some ProductService
that requires authentication can just trust the jwt (it knows the secret) without making any calls to other services (i.e. UserService
which has to query the database).
如果与用户相关的键不是硬性要求,请考虑频繁旋转键,而不要使用jwt的kid
属性.
If user-related keys are not a hard requirement consider rotating the keys frequently instead by making use of jwt's kid
property.
这篇关于将'nestjs/jwt'签名与动态/与用户相关的秘密一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!