我正在使用 Angular、NestJS 和 PostgreSQL 构建全栈项目。尝试使用 Auth0 构建 Authn 和 Authz。用户可以将数据存储在数据库中,其中一列是来自 Auth0 的唯一子 ID。我的想法是:当用户登录客户端并想要检索数据时,向服务器发出请求,其中应该使用 DB-Sub 检查客户端 JWT-Sub。
所以问题来了。检索客户端令牌并将其发送到服务器,但此 Guard 出现错误:
PS:快速编辑。当我在 Postman 中手动传递 JWT 令牌时,请求正常,数据已完全检索。也许是客户端的问题?
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
handleRequest(
...args: Parameters<
InstanceType<ReturnType<typeof AuthGuard>>['handleRequest']
>
) {
console.log(args);
return super.handleRequest(...args);
}
}
这是错误:
[
null,
false,
JsonWebTokenError: jwt malformed
at module.exports [as verify] (C:\Projects\dnd-server\node_modules\jsonwebtoken\verify.js:70:17)
at module.exports [as JwtVerifier] (C:\Projects\dnd-server\node_modules\passport-jwt\lib\verify_jwt.js:4:16)
at C:\Projects\dnd-server\node_modules\passport-jwt\lib\strategy.js:104:25
at JwtStrategy.secretProvider [as _secretOrKeyProvider] (C:\Projects\dnd-server\node_modules\jwks-rsa\src\integrations\passport.js:42:14)
at JwtStrategy.authenticate (C:\Projects\dnd-server\node_modules\passport-jwt\lib\strategy.js:99:10)
at attempt (C:\Projects\dnd-server\node_modules\passport\lib\middleware\authenticate.js:378:16)
at authenticate (C:\Projects\dnd-server\node_modules\passport\lib\middleware\authenticate.js:379:7)
at C:\Projects\dnd-server\node_modules\@nestjs\passport\dist\auth.guard.js:88:3
at new Promise (<anonymous>)
at C:\Projects\dnd-server\node_modules\@nestjs\passport\dist\auth.guard.js:80:83,
ExecutionContextHost {
args: [ [IncomingMessage], [ServerResponse], [Function: next] ],
constructorRef: [class CharacterController],
handler: [AsyncFunction: findOne],
contextType: 'http',
getRequest: [Function: getRequest],
getResponse: [Function: getResponse],
getNext: [Function: getNext]
},
undefined
]
这是我的
auth.strategy.ts
:
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import * as jwksRsa from 'jwks-rsa';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
// Extract JWT from the Authorization header
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
// Validate the token's issuer and audience
issuer: `https://${process.env.AUTH0_DOMAIN}/`,
audience: process.env.AUTH0_AUDIENCE,
// Use Auth0's public key to verify the token's signature
secretOrKeyProvider: jwksRsa.passportJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`,
}),
algorithms: ['RS256'],
});
}
async validate(payload: any) {
return {
sub: payload.sub, // 'sub' claim
};
}
}
这是我的
character.controller.ts
,我从数据库检索数据:
import {
Body,
Controller,
Get,
Param,
Post,
Req,
UseGuards,
} from '@nestjs/common';
import { CharacterService } from './character.service';
import { Character } from './character.model';
import { JwtAuthGuard } from 'src/auth/auth.guard';
@Controller('character')
export class CharacterController {
constructor(private readonly characterService: CharacterService) {}
@Post()
async create(@Body() character: Character): Promise<Character> {
const createdCharacter = await this.characterService.create(character);
console.log('Character created successfully:', createdCharacter);
return createdCharacter;
}
@Get(':id')
@UseGuards(JwtAuthGuard)
async findOne(@Param('id') id: string, @Req() req): Promise<Character> {
const sub = req.user?.sub;
if (!sub) {
console.error("The 'sub' parameter is undefined or null.");
throw new Error("Invalid 'sub' parameter");
}
console.log('Server SUB:', sub);
const character = await this.characterService.findOne(+id);
if (!character) {
console.error(`Character with ID ${id} not found.`);
throw new Error('Character not found');
}
if (character.sub !== sub) {
console.error(
`Server SUB ${sub} does not match character sub ${character.sub}.`,
);
throw new Error('Unauthorized access');
}
return character;
}
}
这是我的
creator.component.ts
的一部分,我试图向服务器发出请求:
saveFormDataToFile() {
const data = this.characterCreationForm.value;
this.http.post("http://localhost:3000/character", data).subscribe(
(response) => {
console.log("Form data saved successfully:", response);
},
(error) => {
console.error("Error saving form data:", error);
}
);
}
retrieveFormDataFromServer(id: number) {
const authToken = this.auth.idTokenClaims$;
authToken.subscribe((token) => {
if (token) {
const headers = new HttpHeaders().set(
"Authorization",
`Bearer ${token.__raw}`
);
console.log("FULL TOKEN:", token);
console.log("Access token retrieved successfully:", token.__raw);
this.http
.get(`http://localhost:3000/character/${id}`, { headers })
.subscribe(
(response: any) => {
console.log("Form data retrieved successfully:", response);
this.characterCreationForm.patchValue(response);
},
(error) => {
console.error("Error retrieving form data:", error);
}
);
} else {
console.error("Error retrieving access token.");
}
});
}
我是个白痴。在我的角度 app.module.ts 中,它是: allowedList: ["http://localhost:3000/*"],
删除“*”,现在可以使用了。