【问题标题】:AuthGuard loaded before AuthServiceAuthGuard 在 AuthService 之前加载
【发布时间】:2021-02-16 22:04:18
【问题描述】:

我正在开发一个小型个人应用程序。我将解释我到目前为止所做的事情,最后是我的问题和我的问题。 我创建了一个节点服务器和一个 Angular 应用程序。 当 Angular 应用程序启动时,我正在检查用户是否已登录(通过对服务器的 http get 请求,请求是在 app.component.ts 中发出的)

      ngOnInit(): void {
    this.authService.checkIfUserSignedIn();
  }

在之后的 checkIfUserSignedIn 方法中,我获得了相关的身份验证信息,我将其通知给具有身份验证状态的感兴趣的组件。

this.userAuthDetailsSubject.next(this.userAuthDetails);

此外,我有一个 AuthGuard,它将“创建列表”组件的条目仅限于经过身份验证的用户。 在 AuthGurad 中,我正在检查身份验证状态:

const authStatus = this.authService.isAuth();
return authStatus;

在菜单 html 组件中,我有以下代码:

<span routerLink="create-list" *ngIf="userIsAuthenticated"> New List</span>

效果很好。 我的问题是当我手动访问 localhost:4200/create-list

AuthGuard 可能在身份验证状态更新之前加载,因此用户无法访问“create-list”组件,尽管他最终已登录。

我考虑了两个解决方案,但我不确定它们是否好用以及如何实施它们,并想听听您的意见。

  1. 使用 localStorage(对于这个小问题,这可能是一种矫枉过正的解决方案)
  2. 在 authGuard 内向服务器发出 HTTP 获取请求(用于 auth 状态),或者订阅 auth 服务中的观察者(如果是,如何实现?)

有什么想法/解决方案吗?


可以激活(AuthGuard):

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | import("@angular/router").UrlTree | import("rxjs").Observable<boolean | import("@angular/router").UrlTree> | Promise<boolean | import("@angular/router").UrlTree> {
    const authStatus = this.authService.isAuth();
    if (authStatus) {
        return true;
    } else {
        this.router.navigate(['/login']);
    }
}

auth.service.ts

@Injectable()
export class AuthService {
    userAuthDetailsSubject = new Subject<UserAuthDetails>();
    userAuthDetails: UserAuthDetails = null;
    private isAuthenticated = false;
    constructor(@Inject(DOCUMENT) private document: Document, private http: HttpClient) {

    };

    public isAuth(): boolean {
        console.log({
            isAuth: this.isAuthenticated
        })
        return this.isAuthenticated;
    }

    signIn() {
        // redirect to signin..
        this.document.location.href = '/auth/google';
    }

    signOut() {
        this.document.location.href = '/auth/logout';
    }

    checkIfUserSignedIn() {
        this.http.get<any>('/auth/current_user').subscribe(res => {
            if (res) {
                this.isAuthenticated = true;
                console.log('assigning true to isAuth')
                this.userAuthDetails = {
                    displayName: res.displayName,
                    email: res.email,
                    uid: res._id
                };
                this.userAuthDetailsSubject.next(this.userAuthDetails);
            } else {
                console.log('User not authenticated')
            }
        })
    }
}

【问题讨论】:

    标签: javascript angular authentication


    【解决方案1】:

    题外话:

    1. 你为什么使用import("@angular/router").UrlTree?您可以使用 import { UrlTree } from '@angular/router'; 之类的导入
    2. CanActive 支持 UrlTree 返回。 return this.router.createUrlTree(['/login']); 并且不在您的 canActivate 中创建新的异步进程

    主题: 如果您调用直接链接,则必须解析身份验证。如果您调用链接或 F5 重新加载浏览器将丢失内存中的所有数据。如果您使用任何令牌进行身份验证,则值得将其保存到 localStore 并从此处恢复。 Ofc,如果您打开新选项卡,则在身份验证后,此新选项卡将在没有身份验证的情况下新建,就像您在当前选项卡上使用 F5 一样。它为每个标签过着不同的生活。

    【讨论】:

    • 谢谢,我改成了 UrlTree (可能也是因为自动完成)
    • 关于身份验证,我没有使用令牌。我的身份验证基于 cookie。我知道当发生直接链接调用时我需要处理身份验证,您对如何实施有建议吗?
    • 如果使用cookie什么时候可以使用angular.io/api/common/http/HttpRequest#withCredentials你想到了吗?
    【解决方案2】:

    对于这个特定问题,您可以将“isAuthenticated”字段设置为类似于“userAuthDetailsS​​ubject”的主题,并在服务器响应时更新其值。

    auth.service.ts

        checkIfUserSignedIn() {
        this.http.get<any>('/auth/current_user').subscribe(res => {
            if (res) {
                this.isAuthenticated.next(true);    //update the value
                console.log('assigning true to isAuth')
                this.userAuthDetails = {
                    displayName: res.displayName,
                    email: res.email,
                    uid: res._id
                };
                this.userAuthDetailsSubject.next(this.userAuthDetails);
            } else {
                console.log('User not authenticated')
            }
    
        })
    }
    

    现在更改您的 authguard,使其不会同步返回 true 或 false。

    可以激活(AuthGuard):

        canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): 
             boolean | import("@angular/router").UrlTree | 
              import("rxjs").Observable<boolean | import("@angular/router").UrlTree>| Promise<boolean | import("@angular/router").UrlTree> {
    
    
              return this.authService.isAuth().subscribe((logged)=>{
                if (logged) {
                  return true;
                } else {
                 this.router.navigate(['/login']);
                 return false;
                }
              })
           }
             
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多