Angular OpenId Connect:第一次渲染发生在令牌准备好之前

Angular OpenId Connect : first rendering occurs before token is ready

我正在使用 Angular 10 和 angular-auth-oidc-client (https://github.com/damienbod/angular-auth-oidc-client).

如果用户未登录(无登录按钮),我希望将用户重定向到身份验证服务器。

我这样做了:

// component : 

export class AppComponent implements OnInit {

  constructor(public authService: AuthService) {
  }

  async ngOnInit(): Promise<void> {
    return this.authService.checkAuthAndLogin();
  }
}


// service : 

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  async checkAuthAndLogin(): Promise<void> {
    await this.oidcSecurityService.checkAuth().subscribe((auth) => {
      if (!auth) {
        this.login();
      }
      console.log('is authenticated', auth);
    });
  }

}

// http client interceptor to send tokens to my backend : 

@Injectable()
export class TokenInterceptor implements HttpInterceptor {
  constructor(
    private oidcSecurityService: OidcSecurityService
  ) {
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    request = request.clone({
      setHeaders: {
        Authorization: `Bearer ${this.oidcSecurityService.getToken()}`
      }
    });
    return next.handle(request);
  }
}

它正在工作,但第一次渲染总是失败,我必须刷新页面才能让它工作。它在第一次加载时向我的后端服务器发送一个空令牌。

我找到了一个解决方法,就是在 init 方法中等待 500 毫秒,但它看起来很脏:

export class AppComponent implements OnInit {

  constructor(public authService: AuthService) {
  }

  loggedIn = false;

  async ngOnInit(): Promise<void> {
    return this.authService.checkAuthAndLogin().then(() => {
      
      return new Promise(resolve => setTimeout(resolve, 500)).then(() => {
        this.loggedIn = true;
      });
    });
  }
}

在我的应用程序组件模板中:

 <div *ngIf="loggedIn">
  [...]
 </div>

它的行为就像 oidcSecurityService.checkAuth() 提前解析,而令牌尚未准备好。

是否有更清洁的解决方案?

谢谢

我认为您没有返回正确的结果:

 checkAuthAndLogin(): Promise<string> {
 return new Promise((res, rej) => {
   this.oidcSecurityService.checkAuth().subscribe((auth) => { // don't user await with observables
      if (!auth) {
        this.login();
        rej('Auth is failed')
      }
      console.log('is authenticated', auth);
      if (auth) res('authenticated');
    });
 })
    
  }

您调用 checkAuthAndLogin 时似乎没有返回任何内容。我不确定您的身份验证服务一起做了什么。但是您需要等待身份验证令牌收到,然后使其登录为真并解决承诺,或者您可以使用行为主题来实现它。

我删除了服务中的 async/await(编辑:和 gnInit 中的异步),我用 ng-if 保留了 isLogged 布尔值(仍然不知道我需要做什么),现在它正在工作:

checkAuthAndLogin(): Observable<void> {
    return this.oidcSecurityService.checkAuth().pipe(map((auth) => {
      if (!auth) {
        this.login();
      }
      console.log('is authenticated', auth);
    }));
  }

// componenent : 
ngOnInit(): Promise<void> {
    return this.authService.checkAuthAndLogin().toPromise().then(() => {
      this.loggedIn = true;
    });
  }