简体   繁体   English

AuthGuard 在 AuthService 之前加载

[英]AuthGuard loaded before AuthService

I'm working on a small personal app.我正在开发一个小型个人应用程序。 I'll explain what I did until now and in the end my problem and my question.我会解释直到现在我做了什么,最后我的问题和我的问题。 I have created a Node server and an Angular app.我创建了一个 Node 服务器和一个 Angular 应用程序。 When the Angular app is booting I'm checking if the user is logged in (via http get request to the server, the request is made in app.component.ts)当 Angular 应用程序启动时,我正在检查用户是否已登录(通过向服务器发送 http get 请求,请求是在 app.component.ts 中进行的)

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

Inside the checkIfUserSignedIn method after that I'm getting the relevant authentication information I notify to the interested components with the auth state.之后在 checkIfUserSignedIn 方法中,我获得了相关的身份验证信息,我将其通知给具有身份验证状态的感兴趣的组件。

this.userAuthDetailsSubject.next(this.userAuthDetails);

Additionally, I'm having an AuthGuard that restrict the entry to the "create-list" component only to authenticated users.此外,我有一个 AuthGuard,它将“创建列表”组件的条目限制为仅经过身份验证的用户。 In the AuthGurad I'm checking the auth state:在 AuthGurad 我正在检查身份验证状态:

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

In the menu html component I have the following code:在菜单 html 组件中,我有以下代码:

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

Which works fine.哪个工作正常。 My problem is when i'm visiting manually localhost:4200/create-list我的问题是当我手动访问 localhost:4200/create-list

The AuthGuard is probably loaded before auth state is updated and therefore the user has no access to the "create-list" component, although he is signed in eventually. AuthGuard 可能在更新身份验证状态之前加载,因此用户无权访问“创建列表”组件,尽管他最终已登录。

I thought about two solutions but I'm not sure if they are good and how to implement them, and would like to hear your opinion.我想到了两种解决方案,但我不确定它们是否好以及如何实施它们,并想听听您的意见。

  1. using localStorage (It may be an overkill solution for this tiny problem)使用 localStorage(对于这个小问题,这可能是一个矫枉过正的解决方案)
  2. make the HTTP get request to the server (for the auth state) inside the authGuard or maybe subscribe to an observer in the auth service (if so, how to implement that?)在 authGuard 内向服务器发出 HTTP get 请求(用于身份验证状态),或者订阅身份验证服务中的观察者(如果是这样,如何实现?)

Any ideas/solutions?任何想法/解决方案?


canActivate (AuthGuard): canActivate (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 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')
            }
        })
    }
}

For this particular problem you can make the 'isAuthenticated' field a subject just like 'userAuthDetailsSubject' and update its value when the server responds.对于此特定问题,您可以将“isAuthenticated”字段设为主题,就像“userAuthDetailsS​​ubject”一样,并在服务器响应时更新其值。

auth.service.ts 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')
        }

    })
}

Now change your authguard so it does not return true or false synchronously.现在更改您的 authguard,使其不会同步返回 true 或 false。

canActivate (AuthGuard): canActivate (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;
            }
          })
       }
         

Off topic:题外话:

  1. Why do you use import("@angular/router").UrlTree ?为什么要使用import("@angular/router").UrlTree You can use import like import { UrlTree } from '@angular/router';你可以像import { UrlTree } from '@angular/router';一样使用 import import { UrlTree } from '@angular/router';
  2. CanActive support UrlTree return. CanActive 支持 UrlTree 返回。 return this.router.createUrlTree(['/login']); and not create a new async process in your canActivate而不是在你的 canActivate 中创建一个新的异步进程

On Topic: If you call direct link, you have to resolve authentication.主题:如果你调用直接链接,你必须解决身份验证。 If you call link or F5 reload browser will lost every data from memory.如果您调用链接或 F5 重新加载浏览器将丢失内存中的所有数据。 If you use any token to auth it be worth saving into localStore and restore from here.如果您使用任何令牌进行身份验证,则值得保存到 localStore 并从此处恢复。 Ofc, After authentication if you open new tab, this new tab will new without auth default like you used F5 on current tab. Ofc,如果您打开新选项卡,则在身份验证后,此新选项卡将在没有身份验证默认值的情况下新建,就像您在当前选项卡上使用 F5 一样。 It lives a separate life for each tabs.每个标签都有不同的生活。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM