我目前正在开发Angular 4应用程序。
应用程序使用Auth0进行身份验证,其语法与其他身份验证服务的语法非常相似。
身份验证代码如下所示:
// auth.services.ts
@Injectable()
export class Auth {
public lock = new Auth0Lock(myConfig.clientID, myConfig.domain, myConfig.lock);
public userProfile: any;
public idToken: string;
public signUpIncomplete: boolean;
// Configure Auth0
private auth0 = new Auth0.WebAuth({
domain: myConfig.domain,
clientID: myConfig.clientID,
redirectUri: myConfig.redirectUri,
responseType: myConfig.responseType
});
// Create a stream of logged in status to communicate throughout app
private loggedIn: boolean;
private loggedIn$ = new BehaviorSubject<boolean>(this.loggedIn);
constructor(private router: Router, private http: Http) {
// Set userProfile attribute of already saved profile
this.userProfile = JSON.parse(localStorage.getItem('profile'));
}
public isAuthenticated(): boolean {
// Check whether the id_token is expired or not
console.log("isAuthenticated");
return tokenNotExpired('id_token');
}
public login(username?: string, password?: string): Promise<any> {
if (!username && !password) {
return;
}
return this.processLogin(username, password);
}
public logout() {
// Remove tokens and profile and update login status subject
localStorage.removeItem('token');
localStorage.removeItem('id_token');
localStorage.removeItem('profile');
this.idToken = '';
this.userProfile = null;
this.setLoggedIn(false);
// Go back to the home rout
this.router.navigate(['/']);
}
public loginWithWidget(): void {
this.lock.show();
}
// Call this method in app.component
// if using path-based routing <== WE ARE USING PATH BASED ROUTING
public handleAuth(): void {
// When Auth0 hash parsed, get profile
this.auth0.parseHash({}, (err, authResult) => {
if (authResult && authResult.accessToken && authResult.idToken) {
// window.location.hash = '';
this._getProfile(authResult);
this.router.navigate(['/']);
} else if (err) {
this.router.navigate(['/']);
console.error(`Error: ${err.error}`);
}
});
}
private setLoggedIn(value: boolean) {
// Update login status subject
this.loggedIn$.next(value);
this.loggedIn = value;
}
private _getProfile(authResult) {
// Use access token to retrieve user's profile and set session
// const lock2 = new Auth0Lock(myConfig.clientID, myConfig.domain, myConfig.lock)
const idToken = authResult.id_token || authResult.idToken;
this.lock.getProfile(idToken, (error, profile) => {
if (error) {
// Handle error
console.error(error.error);
return;
}
// Save session data and update login status subject
this._setSession(authResult, profile);
if (!this.checkUserHasRole(profile)) {
this.router.navigate(['/signup/complete']);
}
});
}
private _setSession(authResult, profile) {
// Save session data and update login status subject
localStorage.setItem('token', authResult.access_token || authResult.accessToken);
localStorage.setItem('id_token', authResult.id_token || authResult.idToken);
localStorage.setItem('profile', JSON.stringify(profile));
this.idToken = authResult.id_token || authResult.idToken;
this.setLoggedIn(true);
this.userProfile = profile;
this.checkUserHasRole(profile);
}
private processLogin(username?: string, password?: string): Promise<any> {
const options = {
client_id: myConfig.clientID,
connection: postConfig.body.connection,
grant_type: 'password',
username,
password,
scope: myConfig.scope
};
const headers = new Headers();
headers.append('content-type', 'application/json');
const reqOpts = new RequestOptions({
method: RequestMethod.Post,
url: postConfig.urlLogin,
headers,
body: options
});
return this.http.post(postConfig.urlLogin, options, reqOpts)
.toPromise()
.then(this.extractData)
.then((data) => { this._getProfile(data); })
.catch(this.handleLoginError);
}
...
}
我遇到的问题是在页面加载时调用isAuthenticated
方法超过1000次。此外,每次在窗口对象中移动鼠标时都会调用它。
虽然我一步一步地遵循了Auth0的教程,但我认为这不是预期的行为,因为它会影响应用程序的性能。
经常被称为isAuthenticated的事实可能是什么原因?我是否必须实现一个定时器,它在指定时间后定期检查或者是否必须实现观察者?我的代码中是否有明显的错误?
答案 0 :(得分:4)
调用isAuthenticated
这么多次的原因取决于调用它的组件,这是你没有的。在此服务中永远不会调用isAuthenticated
一次。
设置路由器防护,改为由Angular API调用CanActivate
。这将在路由激活时调用,并且在路由组件甚至可以加载之前可能会在失败时发生重定向,并且只会被调用一次。用它来代替service.isAuthenticated
。
<强> login.guard.ts 强>
import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router';
import { Auth } from './auth.service';
@Injectable()
export class LoginGuard implements CanActivate {
constructor(public auth: Auth, protected router: Router) { }
canActivate() {
if (!this.auth.isAuthenticated()) {
this.router.navigate(['/']);
return false;
}
return true;
}
在您的路线定义中
export const routes: Routes = [
{ path: '', component: SomeComponent },
{ path: 'main', component: ProtectedComponent, canActivate: [LoginGuard] }
]
在任何情况下都不应该被调用1000次。我猜你的组件或注入树中有一些循环。
答案 1 :(得分:-1)
最后,我找到了原因。
我的导航组件使用主机侦听器@HostListener('mouseover', ['$event'])
实现过渡效果。我不小心将主机监听器添加到了窗口对象中。出于这个原因,每次我移动鼠标时都会触发主机监听器。由于我的导航模板包含*ngIf="auth.isAuthenticated()"
以显示一些导航项目以防用户进行身份验证,因此isAuthenticated
被解雇了很多次。