将'nestjs/jwt'签名与动态/与用户相关的秘密一起使用 [英] Using 'nestjs/jwt' signing with dynamic/user-related secret

查看:324
本文介绍了将'nestjs/jwt'签名与动态/与用户相关的秘密一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试根据尝试登录的用户的机密信息创建用户令牌.但是,我不想使用环境中的机密信息,而是要使用分配给数据库内部用户对象的机密信息.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆