Nest.js
V8.1.2 |
|
プロジェクトは、Nest.js 8.x
バージョンに基づいており、Nest.js 9.x
バージョンとは異なります。次の記事では、これらのバージョン間の違いを具体的に整理しています。 V8
から V9
にアップグレードする手順と方法については、ここでは説明しません。
まず、Nest.js プロジェクトで Redis を接続します。Redis の接続に必要なパラメーター:
REDIS_HOST:Redis 域名
REDIS_PORT:Redis 端口号
REDIS_DB: Redis 数据库
REDIS_PASSPORT:Redis 设置的密码
パラメーターを .env
と .env に書き込みます。 .prod
設定ファイル内:
Nest によって公式に推奨されている方法を使用します。必要な手順は 3 つの簡単な手順だけです:
1. 依存関係を導入します。 files
npm install cache-manager --save
npm install cache-manager-redis-store --save
npm install @types/cache-manager -D
Nest
さまざまなキャッシュ ストレージに統合された API を提供します。組み込みのデータ ストレージはメモリ内にありますが、cache-manager
を使用して他のソリューションを使用してください。たとえば、キャッシュには Redis
を使用します。
キャッシュを有効にするには、ConfigModule
をインポートし、register()
または registerAsync()
を呼び出して応答構成パラメーターを渡します。
2. モジュール ファイル src/db/redis-cache.module.ts
を作成し、次のように実装します:
import { ConfigModule, ConfigService } from '@nestjs/config';
import { RedisCacheService } from './redis-cache.service';
import { CacheModule, Module, Global } from '@nestjs/common';
import * as redisStore from 'cache-manager-redis-store';
@Module({
imports: [
CacheModule.registerAsync({
isGlobal: true,
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => {
return {
store: redisStore,
host: configService.get('REDIS_HOST'),
port: configService.get('REDIS_PORT'),
db: 0, //目标库,
auth_pass: configService.get('REDIS_PASSPORT') // 密码,没有可以不写
};
},
}),
],
providers: [RedisCacheService],
exports: [RedisCacheService],
})
export class RedisCacheModule {}
-
CacheModule
registerAsync
メソッドは Redis ストア構成を使用して
-
store
'cache-manager-redis-store' ライブラリを示す属性値 redisStore
##AppModule- に
RedisCacheModule
をインポートするとき、
#isGlobal プロパティは
true に設定され、グローバル モジュールとして宣言されます。
設定ファイルにRedisの情報が記述されているため、非同期データの処理には- registerAsync()
メソッドを使用します静的データの場合は、
register
3 を使用して、新しい redis-cache.service.ts ファイルを作成し、キャッシュの読み取りおよび書き込み
import { Injectable, Inject, CACHE_MANAGER } from '@nestjs/common';
import { Cache } from 'cache-manager';
@Injectable()
export class RedisCacheService {
constructor(
@Inject(CACHE_MANAGER)
private cacheManager: Cache,
) {}
cacheSet(key: string, value: string, ttl: number) {
this.cacheManager.set(key, value, { ttl }, (err) => {
if (err) throw err;
});
}
async cacheGet(key: string): Promise<any> {
return this.cacheManager.get(key);
}
}
# を実装できます。サービス内の ## 接続 ダウンして、app.module.ts に RedisCacheModule
をインポートします。
トークンの発行と検証プロセスを調整する
Redis を使用して、トークンの有効期限処理、自動トークン更新、および一意のユーザー ログインを実装します。
有効期限処理: ユーザー情報とトークンを redis に配置し、有効期限を設定します。
- トークンの自動更新: トークンの有効期限は 30 分です (30 分以内の場合)。操作が無い場合は、再度ログインしてください。使用中の切断を防ぐため、30分以内に操作があった場合、トークンは自動的に更新されます。
- 各ユーザーに固有のログイン: 同じアカウント、別のコンピューターへのログイン、最初にログインしたユーザーは、後でログインしたユーザーによってオフラインにプッシュされます
-
トークンの有効期限の処理ログイン後 このとき、jwtで生成したトークンをredisに格納し、有効期限を30分に設定します。 redis に格納される key はユーザー情報で構成され、value はトークン値です。 // auth.service.ts
async login(user: Partial<User>) {
const token = this.createToken({
id: user.id,
username: user.username,
role: user.role,
});
+ await this.redisCacheService.cacheSet(
+ `${user.id}&${user.username}&${user.role}`,
+ token,
+ 1800,
+ );
return { token };
}
トークンを検証する場合は、redis からトークンを取得してください。トークンが取得できない場合は、トークンの有効期限が切れている可能性があります。 // jwt.strategy.ts
+ import { RedisCacheService } from './../core/db/redis-cache.service';
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,
private readonly authService: AuthService,
private readonly configService: ConfigService,
+ private readonly redisCacheService: RedisCacheService,
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: configService.get('SECRET'),
+ passReqToCallback: true,
} as StrategyOptions);
}
async validate(req, user: User) {
+ const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req);
+ const cacheToken = await this.redisCacheService.cacheGet(
+ `${user.id}&${user.username}&${user.role}`,
+ );
+ if (!cacheToken) {
+ throw new UnauthorizedException('token 已过期');
+ }
const existUser = await this.authService.getUser(user);
if (!existUser) {
throw new UnauthorizedException('token不正确');
}
return existUser;
}
}
ユーザーのみのログイン
ユーザーがログインすると、発行された新しいトークンが以前のトークンを上書きし、redis 内のトークンと受信リクエストがトークンであるかどうかを判断します。同じでしょうか?そうでない場合は、ユーザーが別の場所でログインしており、トークン エラーが表示されている可能性があります。 // jwt.strategy.ts
async validate(req, user: User) {
const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req);
const cacheToken = await this.redisCacheService.cacheGet(
`${user.id}&${user.username}&${user.role}`,
);
if (!cacheToken) {
throw new UnauthorizedException('token 已过期');
}
+ if (token != cacheToken) {
+ throw new UnauthorizedException('token不正确');
+ }
const existUser = await this.authService.getUser(user);
if (!existUser) {
throw new UnauthorizedException('token不正确');
}
return existUser;
}
トークンの自動更新
多くの実装ソリューションがあり、access_token (jwt は 30 分間有効) と
を生成できます。背景 jwt refresh_token、
refresh_token の有効期間は
access_token よりも長くなります。クライアントはこれら 2 つのトークンをキャッシュします。
access_token の有効期限が切れると、クライアントは ## を保持します。 # 再度、refresh_token
新しい access_token
を取得します。この解決策には、インターフェイス呼び出しの開発者の協力が必要です。
ここではピュアバックエンドで実装したトークンの自動更新を中心に紹介します
実装プロセス:
①: jwtがトークンを生成する際の有効期限は [有効期限なし] に設定されています。
- ②: Redis がトークンをキャッシュするときに有効期間を 30 分に設定します。
- ③: ユーザーがトークン リクエストを送信するとき、キーが存在し、値が同様に、有効期間は 30 分にリセットされます
- jwt によって生成されたトークンが期限切れにならないように設定します。コードのこの部分は
auth.module.ts## にあります。 # ファイル。理解できない場合は、記事 Nest.js 実践シリーズ パート 2 - 登録、スキャン コード ログイン、JWT 認証の実装
// auth.module.ts
const jwtModule = JwtModule.registerAsync({
inject: [ConfigService],
useFactory: async (configService: ConfigService) => {
return {
secret: configService.get('SECRET', 'test123456'),
- signOptions: { expiresIn: '4h' }, // 取消有效期设置
};
},
});
を読んでから、使用されている cache-manager が直接更新されていないため、トークン認証が通過した後の有効期限です。 有効期間メソッドは、リセットすることで実装されます: // jwt.strategy.ts
async validate(req, user: User) {
const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req);
const cacheToken = await this.redisCacheService.cacheGet(
`${user.id}&${user.username}&${user.role}`,
);
if (!cacheToken) {
throw new UnauthorizedException('token 已过期');
}
if (token != cacheToken) {
throw new UnauthorizedException('token不正确');
}
const existUser = await this.authService.getUser(user);
if (!existUser) {
throw new UnauthorizedException('token不正确');
}
+ this.redisCacheService.cacheSet(
+ `${user.id}&${user.username}&${user.role}`,
+ token,
+ 1800,
+ );
return existUser;
}
この時点で、トークンの有効期限処理は、トークンの自動更新、ユーザーのみのログインはNestで完了します。ログアウト時にトークンを削除する方が簡単です。コードを1つずつ示します。
Nest で公式に推奨されている方法を使用することに加えて、nestjs-redis
を使用して実装することもできます。トークンを保存したい場合は、 を保存します。 cache-manager-redis-store
を使用すると、hash
値の保存および取得メソッドがないことがわかります (これを見つけるには多少の労力がかかります) )。 <blockquote><p>注: <code>nest-redis
を使用して Redis キャッシュを実装すると、Nest.js 8 バージョンでエラーが報告されます。友人は @chenjm/nestjs-redis# を使用できます。 # # 代わりに、または問題の解決策を参照してください:
Nest 8 redis bug。
概要
ソースコードのアドレス: https://github.com/koala-coding/nest-blogその他のプログラミング関連知識については、プログラミング教育をご覧ください。 !