问题
I am trying to set up a very simple login system using jwt-passport with nestjs. I followed this tutorial: https://docs.nestjs.com/techniques/authentication but I just can't get it to work. I am really new to this stuff and would appreciate if anyone can show me the way.
The way I send the login to the server:
this.clientAuthService.login(this.userName, this.password).then(response => {
this.clientAuthService.setToken(response.access_token);
this.router.navigate(['/backend']);
});
My ClientAuthService:
export class ClientAuthService {
constructor(private http: HttpClient, @Inject(PLATFORM_ID) private platformId) {
}
getToken(): string {
if (isPlatformBrowser(this.platformId)) {
return localStorage.getItem(TOKEN_NAME);
} else {
return '';
}
}
setToken(token: string): void {
if (isPlatformBrowser(this.platformId)) {
localStorage.setItem(TOKEN_NAME, token);
}
}
removeToken() {
if (isPlatformBrowser(this.platformId)) {
localStorage.removeItem(TOKEN_NAME);
}
}
getTokenExpirationDate(token: string): Date {
const decoded = jwt_decode(token);
if (decoded.exp === undefined) {
return null;
}
const date = new Date(0);
date.setUTCSeconds(decoded.exp);
return date;
}
isTokenExpired(token?: string): boolean {
if (!token) {
token = this.getToken();
}
if (!token) {
return true;
}
const date = this.getTokenExpirationDate(token);
if (date === undefined) {
return false;
}
return !(date.valueOf() > new Date().valueOf());
}
login(userName: string, password: string): Promise<any> {
const loginData = {username: userName, password};
return this.http
.post(Constants.hdaApiUrl + 'user/login', loginData, {headers: new HttpHeaders({'Content-Type': 'application/json'})})
.toPromise();
}
}
My user.controller.ts
@Controller('user')
export class UserController {
constructor(private readonly authService: AuthService) {
}
@UseGuards(AuthGuard('local'))
@Post('login')
authenticate(@Request() req) {
return this.authService.login(req);
}
}
My user.service.ts
export class UsersService {
private readonly users: User[];
constructor() {
this.users = [
{
userId: 1,
username: 'test',
password: '12345',
}
];
}
async findOne(username: string): Promise<User | undefined> {
return this.users.find(user => user.username === username);
}
}
Then I have the jwt.strategy.ts
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: Constants.jwtSecret,
});
}
async validate(payload: any) {
return { userId: payload.sub, username: payload.username };
}
}
and the local.strategy.ts
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super();
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
Mostly I just followed the tutorial and added some stuff for the client-side by myself.
I missed the part with the UseGuard('local')
for the login route but after I added it I am getting 401 error always.
When I don't use UseGuard('local')
it doesn't matter what I type in the login form. After I submit the details, I get access to the backend even tho it was not correct.
Also, it might be worth to mention that the validate methods in jwt.strategy.ts and local.strategy.ts are marked as not used
in WebStorm.
I know its a lot of code here but I need help because I cannot find any other sources for NestJS auth configuration which is up to date. It feels like the tutorial I followed missed a lot of steps for beginners.
回答1:
Make sure your post body (payload) is identical to the signature of the validate method (it actually has to be username & password).
回答2:
In order to add a bit more context, in the above picture you can find detail where the implementation of the specified signature is mentioned. So it's mandatory to send exact "username" and "password" properties in the body.
Note: if you want to customize the signature of your local strategy service you simply have to pass a new object within the 'super()' for specifying the new properties:
super({
usernameField: 'useremail',
passwordField: 'password'
});
Ref: https://docs.nestjs.com/techniques/authentication
来源:https://stackoverflow.com/questions/58101722/nestjs-authentification-with-jwt-passport-not-working