所以,我在这里尝试使用 .Net Core API 在 Angular 中实现 JWT。当我启动 Angular 服务器并运行应用程序时,会发生以下情况:
我想澄清一下,登录与否取决于 JWT 令牌已作为值存储在 localStorage 中,这意味着 API 调用在某些时候有效,只是没有在正确的时间以某种方式进行验证。
所以,为了揭开谜底,这里是有问题的代码:
这将是 AuthService:
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { User } from 'src/app/models/User';
const httpOptions = {
headers: new HttpHeaders({
'Content-Type':'application/json;charset=UTF-8'
})
}
@Injectable({
providedIn: 'root'
})
export class AuthService{
public loggedIn = false;
constructor(private httpClient:HttpClient) { }
login(user: User){
// Set the User object with the corresponding credentials as the request body
const body = JSON.stringify(user);
// Send the post request with its corresponding headers and body
this.httpClient.post<any>("https://localhost:7054/login", body, httpOptions)
.subscribe(data => {
// Here, the data received from the API is known (as I developed it myself):
// it will only contain the token if successful, and will return a bad request
// with a blank token if it fails, so the only scenario where the token may
// be valid is through a HTTP 200 response.
localStorage.setItem("token", data.token);
});
}
}
这将是 HomeComponent.ts
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthResponse } from 'src/app/models/AuthResponse';
import { User } from 'src/app/models/User';
import Swal from "sweetalert2";
import { AuthService } from 'src/app/services/auth/auth.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent {
user: User = new User();
constructor(private router: Router, private authService:AuthService) {
}
token: AuthResponse = new AuthResponse();
//Login method
login(username: string, password: string) {
// - User authentication
// The verification occurs in the backend for security purposes.
// Validate credentials are not blank
if(username != "" || password != ""){
// Create a new User object, which will be passed to the API as request body
let user = new User();
user.email = username;
user.pass = password;
// Call the auth service
this.authService.login(user);
// If the previous operation went well, the token must be stored, and we should be able to log in
if(localStorage.getItem("token")){
this.router.navigate(['/home']);
}
// If the request returns nothing, the credentials are incorrect, therefore an error alert will be sent, plus the token is set to blank
else{
this.sendError("Credentials are incorrect.")
localStorage.setItem("token", "");
}
}
else{
// If the credentials are blank, therefore an error alert will be sent, plus the token is set to blank
this.sendError("Please type your credentials.")
localStorage.setItem("token", "");
}
}
sendError(error:string){
Swal.fire({
icon: 'error',
title: 'Error',
text: error,
})
}
}
因此,如果有人能指出这种奇怪行为的原因,我将不胜感激。我确信我遗漏了一些东西或者明显做错了,我只是无法指出它。
预先感谢您的帮助。
我尝试使用拦截器来处理响应,但它们似乎对奇怪的行为没有帮助。
我尝试过强制进行令牌验证,但似乎也没有帮助,因为令牌类型会在尝试之间被缓存。
我看到了很多问题。
首先在这里:
if(localStorage.getItem("token")){
this.router.navigate(['/home']);
}
// If the request returns nothing, the credentials are incorrect, therefore an error alert will be sent, plus the token is set to blank
else{
this.sendError("Credentials are incorrect.")
localStorage.setItem("token", "");
}
您的 else 语句正在设置令牌。所以,当一个人第二次点击“登录”时;无论登录成功与否,应用程序都会导航至回家路线。
此外,登录代码是异步的(它应该是这样),但您正在同步运行检查。所以这一段代码(就在我引用的上一节的上方)可能是在登录功能完成之前检查令牌是否存在。
// Call the auth service
this.authService.login(user);
// If the previous operation went well, the token must be stored, and we should be able to log in
if(localStorage.getItem("token")){
一个可能的修复方法是让 authService 返回一个 Observable。另外,使用管道运算符而不是 subscribe() 方法处理令牌。
login(user: User){
// Set the User object with the corresponding credentials as the request body
const body = JSON.stringify(user);
// Send the post request with its corresponding headers and body
return this.httpClient.post<any>("https://localhost:7054/login", body, httpOptions)
.pipe(tap(data => {
// Here, the data received from the API is known (as I developed it myself):
// it will only contain the token if successful, and will return a bad request
// with a blank token if it fails, so the only scenario where the token may
// be valid is through a HTTP 200 response.
localStorage.setItem("token", data.token);
}));
}
我使用了tap,不过在这种情况下可能有更好的运算符可以使用。
然后调整组件代码以订阅 Observable,以便在 login() 方法完成后处理结果:
// Call the auth service
this.authService.login(user).subscribe(() ==> {
// If the previous operation went well, the token must be stored, and we should be able to log in
if(localStorage.getItem("token")){
this.router.navigate(['/home']);
}
// If the request returns nothing, the credentials are incorrect, therefore an error alert will be sent, plus the token is set to blank
else{
this.sendError("Credentials are incorrect.")
localStorage.setItem("token", "");
}
});
我建议您根据服务器返回的错误代码来处理错误,而不是检查令牌是否存在。
免责声明:所有这些代码都是在浏览器中编写的并且未经测试,但应该演示一种替代方法,该方法将修复我见过的一些逻辑错误。