Использование подписи 'nestjs / jwt' с динамическим / пользовательским секретом - PullRequest
4 голосов
/ 26 марта 2019

Я пытаюсь создать токен пользователя, основываясь на секрете пользователя, пытающегося войти в систему. Однако вместо использования секрета из среды я хочу использовать секрет, назначенный объекту пользователя внутри базы данных.

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 предоставляет необходимый параметр в функции sign(...).nestjs/jwt отсутствует этот параметр (см. Код).Как бы вы решили это, не используя node-jsonwebtoken или, может быть, более абстрактный вопрос: имеет ли здесь смысл мой способ обработки секрета пользователя?Спасибо.

1 Ответ

2 голосов
/ 27 марта 2019

Это пока невозможно только с помощью гнезда JwtModule, но вы можете легко реализовать недостающие части самостоятельно.

Live Demo

Edit Nest Dynamic JWT Secrets

Вы можете создавать токены, вызывая следующие маршруты:

user1 (секрет: '123'): https://yw7wz99zv1.sse.codesandbox.io/login/1
user2 (секрет: 456): https://yw7wz99zv1.sse.codesandbox.io/login/2

Затем позвоните по защищенному маршруту '/' со своим токеном и получите своего пользователя:

curl -X GET https://yw7wz99zv1.sse.codesandbox.io/ \
      -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxIiwiaWF0IjoxNTUzNjQwMjc5fQ.E5o3djesqWVHNGe-Hi3KODp0aTiQU9X_H3Murht1R5U'

Как это работает?

В AuthService я просто использую стандартную библиотеку jsonwebtoken для создания токена. Затем вы можете позвонить createToken со своего маршрута входа в систему:

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 для динамического получения секрета пользователя:

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 без параметров:

JwtModule.register({})

Общее

Имеет ли смысл мой способ обработки секрета пользователя?

Трудно ответить, не зная ваших точных требований. Я предполагаю, что есть варианты использования jwt с динамическими секретами, но с этим вы теряете большое свойство jwt: они не сохраняют состояния. Это означает, что ваш AuthService может выдать токен jwt, а некоторые ProductService, требующие аутентификации, могут просто доверять jwt (он знает секрет) без каких-либо вызовов других служб (например, UserService, который должен запрашивать базу данных). .

Если пользовательские ключи не являются жестким требованием, рассмотрите возможность их частого вращения, используя свойство kid jwt.

...