在加载任何组件之前从标头获取身份验证令牌

时间:2020-10-10 09:52:34

标签: angular typescript angular9

我是angel的新手,正在研究修改代码。

当前代码使用默认的角度方法将所有组件加载在一起,这意味着多个组件将一起进行http调用。

我的角度应用程序托管在具有通过azure门户配置的azure广告身份验证的azure应用程序服务上。

从第一点开始,我想改善并确保 首先,在加载任何组件之前,我从http://host/.auth/me url获得id_token参数,这将是我的auth令牌(此auth令牌作为auth标头将用于对后端进行api调用)

一旦我有了此身份验证令牌,就应将其存储在本地/会话存储中。仅在此过程完成后,我才想继续加载其他角度组件。

我已经阅读了有关组件的延迟加载的信息。但我想知道在上述情况下最好的做法是什么。

2 个答案:

答案 0 :(得分:1)

好吧,有多种方法可以做到

APP_INITIALIZER

您可以编写一个加载令牌的异步函数,然后将该函数注入主模块。在解决函数的promise之前,不会初始化任何组件。这种方法很简单但是很丑。在进行令牌请求时,用户将看到白屏。

@NgModule({
  //...
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: () => () => {
        return fetch('https://token.provired.com/getToken')
          .then(x => x.json())
          .then(x => localStorage.setItem("token", x));
      },
      multi: true,
    }
  ]
})
export class AppModule { }

根组件

您可以从根组件初始化令牌请求,通常是app.cpmponent.ts。在组件的模板中,可以在请求进行时显示一些标记或微调框,以使用户知道该应用程序正在运行。其他组件的初始化应该被*ngIf阻止。检查下面的代码段

@Component({
  selector: 'app-root',
  template: `
    <div *ngIf="!tokenLoaded">Please wait</div>
    <div *ngIf="tokenLoaded">
      <app-my-component></app-my-component>
    </div>`,
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
  tokenLoaded = false;

  ngOnInit(){
    getToken().then(token => {
      localStorage.setItem("token", token);
      tokenLoaded = true;
    })
  }
}

后卫

正如评论中提到的@Gytis TG一样,您可以在守护程序中运行令牌请求。这种方法的优点是您将拥有单独的代码来负责令牌的加载。

答案 1 :(得分:1)

我认为我们对如何处理组件的可见性限制有两个想法。

在我们的应用程序中,我们可以在auth.service.ts中处理登录和其他身份验证。

// auth.service.ts
@Injectable({
  providedIn: 'root'
})
export class AuthService {
private token: string;
private loggedIn = false;

constructor(private http: HttpClient) {}


getLoggedIn() {
  return this.loggedIn;
}

login(email:string, password:string): Promise <string> {
  const promise = new Promise < string > ((resolve, reject) => {
    const authData = { email: email, password: password }
      this.http.post < { token: string } > (environment.backendUrl + '/api/user/login', authData).toPromise()
      .then(response => {
         const token = response.token;
         this.token = token;
         if (token) {
           this.loggedIn = true;
         }
}
如您在上面的代码段中看到的,一旦登录成功,我们就会在响应正文中收到一个令牌,我认为这与在应用程序中获取令牌的方式类似。然后将这个response.token分配给auth.service.ts文件中的token变量。在将令牌分配给auth.service.ts文件中的变量后,我们可以读取它并通过导入auth.service.ts文件从应用程序中的任何位置调用getLoggedIn()函数来检查令牌。

现在回到如何通过检查令牌来限制组件的可见性。一种方法是,我们可以将auth.service.ts文件导入到要限制组件可见性的组件中,方法是像这样将其添加到构造函数中

// .ts file where you want to restrict visibility
export class component {
loggedIn = false;

constructor(private authService: AuthService) {}

ngOnInit() {
   this.loggedIn = this.authService.getLoggedIn();
}

您可以看到该组件正在ngOnInit调用期间检查令牌。这意味着在我们相应的html文件中,我们可以将此登录变量与* ngIf一起使用,以限制某些html元素甚至整个组件(如果需要)的可见性

// .html file
<div *ngIf=loggedIn>
   <h1> title </h1>
   <p> here you be your text </p>
</div>

另一种方法是像米哈伊尔和吉蒂斯以前提到的那样实施警卫。该防护程序会在路由到页面之前检查令牌,以确保只有登录的用户才能访问某些页面。我们可以通过添加auth.guard.ts文件来做到这一点:

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(private authService: AuthService, private router: Router) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): boolean | Observable < boolean > | Promise < boolean > {
    const loggedIn = this.authService.getLoggedIn();
    if (!loggedIn) {
      this.router.navigate(['/login']);
    }
    return loggedIn;
  }

}

添加完此文件后,我们可以像这样在app-routing.ts文件中启用令牌检查。

// app-routing.ts file
const routes: Routes = [
    { path: "", component: HomePageComponent },
    { path: "home", component: HomePageComponent },
    { path: "login", component: LoginPageComponent },
    { path: "signup", component: SignupPageComponent },
    { path: "profile/:id", component: ProfilePageComponent, canActivate: [AuthGuard] },

]

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule],
    providers: [AuthGuard]
})
export class AppRoutingModule {}
剪掉的个人资料页面中的

受AuthGuard保护,因此只有登录的用户才能访问此页面。如果未登录用户,则AuthGuard会将用户重定向到登录页面,因此,即使在浏览器中手动键入URL,在访问页面之前仍需要登录。

我对SO也很陌生,但我尽力为您写一个清晰的答案,希望对您有帮助! :)祝您有美好的一天!