[英]Getting User Data by using Guards (Roles, JWT)
這里的文檔有點薄,所以我遇到了一個問題。 我嘗試使用 Guards 來保護 Controller 或它的 Actions,所以我會要求經過身份驗證的請求的作用(通過 JWT)。 在我的 auth.guard.ts 中,我要求“request.user”但它是空的,所以我無法檢查用戶角色。 我不知道如何定義“request.user”。 這是我的 auth 模塊和它的導入。
auth.controller.ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { RolesGuard } from './auth.guard';
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@Get('token')
async createToken(): Promise<any> {
return await this.authService.signIn();
}
@Get('data')
@UseGuards(RolesGuard)
findAll() {
return { message: 'authed!' };
}
}
角色.guard.ts
這里 user.request 是空的,因為我從來沒有定義過它。 文檔沒有顯示如何或在哪里。
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private readonly reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.get<string[]>('roles', context.getHandler());
if (!roles) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user; // it's undefined
const hasRole = () =>
user.roles.some(role => !!roles.find(item => item === role));
return user && user.roles && hasRole();
}
}
auth.module.ts
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { HttpStrategy } from './http.strategy';
import { UserModule } from './../user/user.module';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './jwt.strategy';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secretOrPrivateKey: 'secretKey',
signOptions: {
expiresIn: 3600,
},
}),
UserModule,
],
providers: [AuthService, HttpStrategy],
controllers: [AuthController],
})
export class AuthModule {}
auth.service.ts
import { Injectable } from '@nestjs/common';
import { UserService } from '../user/user.service';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(
private readonly userService: UserService,
private readonly jwtService: JwtService,
) {}
async signIn(): Promise<object> {
// In the real-world app you shouldn't expose this method publicly
// instead, return a token once you verify user credentials
const user: any = { email: 'user@email.com' };
const token: string = this.jwtService.sign(user);
return { token };
}
async validateUser(payload: any): Promise<any> {
// Validate if token passed along with HTTP request
// is associated with any registered account in the database
return await this.userService.findOneByEmail(payload.email);
}
}
jwt.strategy.ts
import { ExtractJwt, Strategy } from 'passport-jwt';
import { AuthService } from './auth.service';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'secretKey',
});
}
async validate(payload: any) {
const user = await this.authService.validateUser(payload);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
文檔: https : //docs.nestjs.com/guards
謝謝你的幫助。
除了RolesGuard
您還需要使用AuthGuard
。
您可以使用將用戶對象附加到請求的標准AuthGuard
實現。 當用戶未經身份驗證時,它會引發 401 錯誤。
@UseGuards(AuthGuard('jwt'))
如果您因為需要不同的行為而需要編寫自己的守衛,請擴展原始AuthGuard
並覆蓋您需要更改的方法(示例中的handleRequest
):
@Injectable()
export class MyAuthGuard extends AuthGuard('jwt') {
handleRequest(err, user, info: Error) {
// don't throw 401 error when unauthenticated
return user;
}
}
如果您查看AuthGuard
的源代碼,您會發現它將用戶附加到請求中,作為對通行證方法的回調。 如果您不想使用/擴展AuthGuard
,則必須實現/復制相關部分。
const user = await passportFn(
type || this.options.defaultStrategy,
options,
// This is the callback passed to passport. handleRequest returns the user.
(err, info, user) => this.handleRequest(err, info, user)
);
// Then the user object is attached to the request
// under the default property 'user' which you can change by configuration.
request[options.property || defaultOptions.property] = user;
您可以將多個守衛連接在一起(@UseGuards(AuthGuard('jwt'), RolesGuard))以在它們之間傳遞上下文。 然后您將可以訪問“RolesGuard”中的“req.user”對象。
如果您使用req.authInfo
是否req.authInfo
?
只要您不為passport.authenticate 方法提供自定義回調,用戶數據就應該像這樣附加到請求對象上。
req.authInfo
應該是您在validate
方法中返回的對象
在我得到選定的答案后(謝謝),我也找到了這個選項,你可以將它添加到基本上做同樣事情的構造函數中。
http://www.passportjs.org/docs/authorize/
驗證回調中的關聯
上述方法的一個缺點是它需要相同策略和支持路線的兩個實例。
為避免這種情況,請將策略的 passReqToCallback 選項設置為 true。 啟用此選項后, req 將作為第一個參數傳遞給驗證回調。
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy, 'local') {
constructor(private authService: AuthService) {
super({
passReqToCallback: true
})
}
// rest of the strategy (validate)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.