我是angel的新手,正在研究修改代码。
当前代码使用默认的角度方法将所有组件加载在一起,这意味着多个组件将一起进行http调用。
我的角度应用程序托管在具有通过azure门户配置的azure广告身份验证的azure应用程序服务上。
从第一点开始,我想改善并确保 首先,在加载任何组件之前,我从http://host/.auth/me url获得id_token参数,这将是我的auth令牌(此auth令牌作为auth标头将用于对后端进行api调用)
一旦我有了此身份验证令牌,就应将其存储在本地/会话存储中。仅在此过程完成后,我才想继续加载其他角度组件。
我已经阅读了有关组件的延迟加载的信息。但我想知道在上述情况下最好的做法是什么。
答案 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也很陌生,但我尽力为您写一个清晰的答案,希望对您有帮助! :)祝您有美好的一天!