在Angular中不使用LocalStorage或Cookie的Auth Guard



我在Angular中实现了一个认证保护,但不是访问本地存储或cookie来检查用户是否经过身份验证,我有一个API端点,如果有一个包含JWT的httponly cookie附加到请求和401 Unauthorized,则返回200 OK

这是我试过

// auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root',
})
export class AuthService {
constructor(
private httpClient: HttpClient,
) {}
login(username: string, password: string) {
return this.httpClient.post('/users/login', { username, password });
}
isLoggedIn(): boolean {
this.httpClient.get('/users/check').subscribe({
next: (data) => {
return true;
},
error: () => {
return false;
},
});
return false;
}
}
// auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(): boolean {
if (!this.authService.isLoggedIn()) {
this.router.navigate(['login']);
return false;
}
return true;
}
}
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { LayoutComponent } from './layout/layout.component';
import { ProjectsComponent } from './projects/projects.component';
import { AuthGuard } from './core/auth/auth.guard';
const routes: Routes = [
{
path: '',
component: LayoutComponent,
canActivate: [AuthGuard],
children: [{ path: 'projects', component: ProjectsComponent }],
},
{ path: 'login', component: LoginComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}

问题发生在用户已经登录并且设置了认证cookie之后,isLoggedIn()函数仍然返回false,从而将用户重定向回登录页面。我的猜测是,这与我错误地处理httpclient的可观察到的东西有关,并在请求完成之前将其导致return false;?

任何帮助都是感激和提前感谢!

这是一个经典的异步处理问题,以及一些函数作用域的理解…

当您这样做时,可以看到两个主要问题:

isLoggedIn(): boolean {
this.httpClient.get('/users/check').subscribe({
next: (data) => {
return true; // issue 02
},
error: () => {
return false;  // issue 02
},
});
return false; // issue 01
}
  • Issue 01:您的函数仅/始终返回false,因为这是isLoggedIn函数范围内唯一的返回语句。(经典的异步问题)

  • Issue 02:订阅中的回调函数被调用,但是它们的返回值没有被使用。(对函数作用域的理解存在问题)。问题是return的我标记为"issue 02"。属于订阅回调函数的作用域,而不属于isLoggedIn函数的作用域。

解决这个问题:

  1. 你应该返回可观察对象,用管道将结果转换为true/false,而不是订阅:
isLoggedIn() {
return this.httpClient.get('/users/check').pipe(
map(() => true),
catchError(() => of(false))
)
}
  1. 从你的guard(在你的服务中有类似的问题),你也不订阅,并相信订阅将由guard的调用者(angular internal)完成:
canActivate() {
return this.authService.isLoggedIn().pipe(take(1), tap(loggedIn => {
if (!loggedIn) this.router.navigate(['login']);
}));
}

试试这个,它对我有用。

内部isLoggedIn函数:

isLoggedIn(): boolean {
return this.httpClient.get('/users/check').subscribe({
next: (data) => {
return true;
},
error: () => {
return false;
},
});
}

Inside canActivate Guard:

canActivate(){
return this.authService.isLoggedIn().subscribe(res => {
if (!res) this.router.navigate(['login']);
else return true;    
});
}

最新更新