NestJS USER AUTHENTICATION
設定
npm i jsonwebtoken
npm i jsonwebtoken @types/jsonwebtoken --only-dev
使用
ConfigModule.SECRET KEYをforRootのvalidationSchemaに追加します.
SECRET KEYはjwtです.signでprivateKeyを使う
app.module.ts
import { Module } from '@nestjs/common';
import * as Joi from 'joi';
import { ConfigModule } from '@nestjs/config';
import { GraphQLModule } from '@nestjs/graphql';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersModule } from './users/users.module';
import { CommonModule } from './common/common.module';
import { User } from './users/entities/user.entity';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true, //우리 어플리케이션의 어디서나 config 모듈에 접근할 수 있다는 것
envFilePath: process.env.NODE_ENV === 'dev' ? '.env.dev' : '.env.test',
ignoreEnvFile: process.env.NODE_ENV === 'prod', //서버에 deply 할 때 환경변수 파일을 사용하지 않는다는 것
validationSchema: Joi.object({
NODE_ENV: Joi.string().valid('dev', 'prod').required(),
DB_HOST: Joi.string().required(),
DB_PROT: Joi.string().required(),
DB_USERNAME: Joi.string().required(),
DB_PASSWORD: Joi.string().required(),
DB_NAME: Joi.string().required(),
SECRET_KEY: Joi.string().required(),
}),
}),
TypeOrmModule.forRoot({
...
}),
GraphQLModule.forRoot({
autoSchemaFile: true, //메모리에 저장
}),
UsersModule,
CommonModule,
],
controllers: [],
providers: [],
})
export class AppModule {}
SECRET KEYを処理します.env.SECRET KEYとしてインポートすることもできますが、configServiceでインポートすることもできます.元のユーザー.modules.tsにconfigサービスを提供する必要がありますが、モジュールを構成するオプションはisGlobal:trueなので、プロバイダを必要とせずに使用できます.
import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { UsesrResolver } from './users.resolver';
import { UsersService } from './users.service';
@Module({
imports: [TypeOrmModule.forFeature([User])],
providers: [UsesrResolver, UsersService],
})
export class UsersModule {}
users.service.tsprivate readonly config:ConfigServiceを宣言して構成します.変数名をget()メソッドのパラメータに渡すことで、環境変数をインポートできます.
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import * as jwt from 'jsonwebtoken';
import { CreateAccountInput } from './dtos/create-account.dto';
import { LoginInput } from './dtos/login.dto';
import { User } from './entities/user.entity';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly users: Repository<User>,
private readonly config: ConfigService,
) {}
//create User
...
//Login User
async login({
email,
password,
}: LoginInput): Promise<{ ok: boolean; error?: string; token?: string }> {
// make a JMT and give it to the user
try {
// find ths user with the email
const user = await this.users.findOne({ email });
if (!user) {
return { ok: false, error: 'User not found' };
}
// check if the passowrd is correct
const passwordCorrect = await user.checkPassword(password);
if (!passwordCorrect) {
return { ok: false, error: 'Wrong password' };
}
const token = jwt.sign({ id: user.id }, this.config.get('SECRET_KEY'));
return { ok: true, token: 'goododo' };
} catch (error) {
return { ok: false, error };
}
}
}
jwt.Signの最初のパラメータはtokenにどのような情報を入れるかを指定し、privateKeyは2番目のパラメータとして入ります.tokenをユーザーに指定すると、ユーザーは自分のtokenに何が含まれているかを表示できます.
これは、ユーザが自分のtokenのパスワードを復号できることを意味する.
したがって、tokenは重要な個人情報を格納するのに適していない.だから私はuserのid値をtokenにあげました
privateKeyを使用してtokenを指定する目的は、ユーザーがtokenの情報を変更する場合です.
privateKeyでユーザーがtokenを変更したかどうかを検証できるからです.
これは,修正後の情報も認識できることを意味する.
nestjsのモジュールは2種類あります
1つ目は静的モジュールです
静的モジュールとは、設定が適用されていないことを意味します.
2つ目はダイナミックモジュールです.
ダイナミックモジュール(Dynamic Module)は、GraphQLModuleと同様に設定されています.
ここで注意すべきは、ダイナミックモジュールが実際には最終的に静的モジュールになることである.
dynamic moduleはまずstatic moduleであり、戻り値はdynamic moduleである.
JWTモジュールの作成
jwtモジュールおよびサービスは、nest g mo jwt、nest g s jwtによって作成される.
JWTモジュールをダイナミックモジュールにするため、jwt.module.tsで:
import { DynamicModule, Global, Module } from '@nestjs/common';
import { JwtService } from './jwt.service';
@Module({})
@Global() // 전역으로 사용가능하게 만들어줍니다. ConfigModule의 isGlobal: true와 같다고 보면됩니다.
export class JwtModule {
// dynamic module은 일단 static module이고 반환값이 dynamic module입니다.
static forRoot(): DynamicModule {
return {
module: JwtModule,
exports: [JwtService],
providers: [JwtService],
};
}
}
jwt.service.tsimport { Injectable } from '@nestjs/common';
@Injectable()
export class JwtService {
hello() {
console.log('Hello');
}
}
app.module.tsこれにより、いつでもどこでも依存性を注入することでJwtServiceを使用できます.
import { Module } from '@nestjs/common';
import * as Joi from 'joi';
import { ConfigModule } from '@nestjs/config';
import { GraphQLModule } from '@nestjs/graphql';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersModule } from './users/users.module';
import { CommonModule } from './common/common.module';
import { User } from './users/entities/user.entity';
import { JwtModule } from './jwt/jwt.module';
@Module({
imports: [
//...설정
JwtModule.forRoot(),
UsersModule,
CommonModule,
],
controllers: [],
providers: [],
})
export class AppModule {}
users.service.tsimport { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import * as jwt from 'jsonwebtoken';
import { CreateAccountInput } from './dtos/create-account.dto';
import { LoginInput } from './dtos/login.dto';
import { User } from './entities/user.entity';
import { ConfigService } from '@nestjs/config';
import { JwtService } from 'src/jwt/jwt.service';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly users: Repository<User>,
private readonly config: ConfigService,
private readonly jwtService: JwtService,
) {
console.log(this.jwtService.hello()); //Hello
}
...
}
console.log.jwtservice.hello出力を見てみましょう.custom provider
プロバイダ:WTServiceの元の形式は、「提供:WTService、ユーザー・クラス:WTService」です.
ベンダーをカスタマイズできます.
import { DynamicModule, Global, Module } from '@nestjs/common';
import { JwtModuleOptions } from './jwt.interfaces';
import { CONFIG_OPTIONS } from './jwt.constants';
import { JwtService } from './jwt.service';
@Module({})
@Global()
export class JwtModule {
static forRoot(options: JwtModuleOptions): DynamicModule {
return {
module: JwtModule,
exports: [JwtService],
providers: [
{
//CONFIG_OPTIONS라는 이름을 가진 provider가 있고 그 value가 options인 것이다
provide: CONFIG_OPTIONS,
useValue: options,
},
JwtService,
],
};
}
}
jwt.constants.tsexport const CONFIG_OPTIONS = 'CONFIG_OPTIONS';
jwt.interfaces.tsexport interface JwtModuleOptions {
privateKey: string;
}
app.module.tsimport { Module } from '@nestjs/common';
import * as Joi from 'joi';
import { ConfigModule } from '@nestjs/config';
import { GraphQLModule } from '@nestjs/graphql';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersModule } from './users/users.module';
import { CommonModule } from './common/common.module';
import { User } from './users/entities/user.entity';
import { JwtModule } from './jwt/jwt.module';
@Module({
imports: [
//...설정
JwtModule.forRoot({
privateKey: process.env.PRIVATE_KEY,
}),
UsersModule,
CommonModule,
],
controllers: [],
providers: [],
})
export class AppModule {}
jwt.service.tsimport { Inject, Injectable } from '@nestjs/common';
import { JwtModuleOptions } from './jwt.interfaces';
import { CONFIG_OPTIONS } from './jwt.constants';
@Injectable()
export class JwtService {
constructor(
@Inject(CONFIG_OPTIONS)
private readonly options: JwtModuleOptions,
) {
console.log(this.options); // {privateKey: 설정한값}
}
sign(userId: number): string {
return jwt.sign({ id: userId }, this.options.privateKey);
}
}
users.service.tsjwtServiceが作成されているので、このように符号化できます.
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateAccountInput } from './dtos/create-account.dto';
import { LoginInput } from './dtos/login.dto';
import { User } from './entities/user.entity';
import { ConfigService } from '@nestjs/config';
import { JwtService } from 'src/jwt/jwt.service';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly users: Repository<User>,
private readonly config: ConfigService,
private readonly jwtService: JwtService,
) {}
//create User
...
//Login User
async login({
email,
password,
}: LoginInput): Promise<{ ok: boolean; error?: string; token?: string }> {
// make a JMT and give it to the user
try {
// find ths user with the email
const user = await this.users.findOne({ email });
if (!user) {
return { ok: false, error: 'User not found' };
}
// check if the passowrd is correct
const passwordCorrect = await user.checkPassword(password);
if (!passwordCorrect) {
return { ok: false, error: 'Wrong password' };
}
// const token = jwt.sign({ id: user.id }, this.config.get('PRIVATE_KEY'));
const token = this.jwtService.sign(user.id);
return { ok: true, token };
} catch (error) {
return { ok: false, error };
}
}
}
Reference
この問題について(NestJS USER AUTHENTICATION), 我々は、より多くの情報をここで見つけました https://velog.io/@abc5259/NestJS-USER-AUTHENTICATIONテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol