我是 Rxjs 的新手。我正在尝试为我的 nativescript-angular 应用程序实现一个 canActivate 保护。基本上,如果用户在存储中有 JWT 令牌,它将尝试从服务器检查 JWT 的有效性,如果令牌仍然有效则登陆主页,如果令牌无效则重定向到登录页面。以下代码在服务器启动时工作正常,但是,当服务器关闭时,它将登陆一个不完整的主页,因为无法从服务器获取数据。发生这种情况是因为同步if(this.authService.isLoggedIn())
不等待异步 http 调用并返回 true(下面的代码)。我希望它通过在服务器关闭时阻塞来重定向到登录页面而不是主页,我尝试了各种方法(甚至重构代码)但它们都不起作用。这个和这个与我的情况非常相似,但解决方案没有帮助。这是我的代码:
编辑:auth.service.ts(更新)
import { getString, setString, remove } from 'application-settings';
interface JWTResponse {
status: string,
success: string,
user: any
};
export class AuthService {
tokenKey: string = 'JWT';
isAuthenticated: Boolean = false;
username: Subject<string> = new Subject<string>();
authToken: string = undefined;
constructor(private http: HttpClient) { }
loadUserCredentials() { //call from header component
if(getString(this.tokenKey)){ //throw error for undefined
var credentials = JSON.parse(getString(this.tokenKey));
if (credentials && credentials.username != undefined) {
this.useCredentials(credentials);
if (this.authToken)
this.checkJWTtoken();
}
}
}
checkJWTtoken() {
this.http.get<JWTResponse>(baseURL + 'users/checkJWTtoken') //call server asynchronously, bypassed by synchronous code in canActivate function
.subscribe(res => {
this.sendUsername(res.user.username);
},
err => {
this.destroyUserCredentials();
})
}
useCredentials(credentials: any) {
this.isAuthenticated = true;
this.authToken = credentials.token;
this.sendUsername(credentials.username);
}
sendUsername(name: string) {
this.username.next(name);
}
isLoggedIn(): Boolean{
return this.isAuthenticated;
}
destroyUserCredentials() {
this.authToken = undefined;
this.clearUsername();
this.isAuthenticated = false;
// remove("username");
remove(this.tokenKey);
}
clearUsername() {
this.username.next(undefined);
}
auth-guard.service.ts
canActivate(route: ActivatedRouteSnapshot,
state:RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean{
this.authService.loadUserCredentials(); //skip to next line while waiting for server response
if(this.authService.isLoggedIn()){ //return true due useCredentials called in the loadUserCredentials
return true;
}
else{
this.routerExtensions.navigate(["/login"], { clearHistory: true })
return false;
}
}
app.routing.ts
const routes: Routes = [
{ path: "", redirectTo: "/home", pathMatch: "full" },
{ path: "login", component: LoginComponent },
{ path: "home", component: HomeComponent, canActivate: [AuthGuard] },
{ path: "test", component: TestComponent },
// { path: "item/:id", component: ItemDetailComponent },
];
Edit2:我尝试了这些代码:
auth-guard.service.ts
canActivate(route: ActivatedRouteSnapshot,
state:RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean{
this.authService.loadUserCredentials();
if(this.authService.isLoggedIn()){
console.log("if");
return true;
}
else{
console.log("else");
this.routerExtensions.navigate(["/login"], { clearHistory: true })
return false;
}
}
auth.service.ts
async checkJWTtoken() {
console.log("checkJWTtoken1")
try{
console.log("try1")
let res = await this.http.get<JWTResponse>(baseURL + 'users/checkJWTtoken').toPromise();
console.log("try2")
this.sendUsername(res.user.username);
console.log("try3")
}
catch(e){
console.log(e);
this.destroyUserCredentials();
}
console.log("checkJWTtoken2")
}
// checkJWTtoken() {
// this.http.get<JWTResponse>(baseURL + 'users/checkJWTtoken')
// .subscribe(res => {
// // console.log("JWT Token Valid: ", JSON.stringify(res));
// this.sendUsername(res.user.username);
// },
// err => {
// console.log("JWT Token invalid: ", err);
// this.destroyUserCredentials();
// })
// }
这是控制台输出:
JS: Angular is running in the development mode. Call enableProdMode() to enable the production mode.
JS: checkJWTtoken1
JS: try1
JS: if
JS: ANGULAR BOOTSTRAP DONE. 6078
JS: try2
JS: try3
JS: checkJWTtoken2
编辑3:
tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"noEmitHelpers": true,
"noEmitOnError": true,
"lib": [
"es6",
"dom",
"es2015.iterable"
],
"baseUrl": ".",
"paths": {
"*": [
"./node_modules/tns-core-modules/*",
"./node_modules/*"
]
}
},
"exclude": [
"node_modules",
"platforms"
]
}
请提前告知和感谢。