J. *_*Doe 1 firebase typescript angular
src
|_auth/
|_authentication/
|_auth-service.ts
|_auth-guard.ts
|_is-logged-guard.ts
|_dashboard/
Run Code Online (Sandbox Code Playgroud)
auth-guard-service.ts
src
|_auth/
|_authentication/
|_auth-service.ts
|_auth-guard.ts
|_is-logged-guard.ts
|_dashboard/
Run Code Online (Sandbox Code Playgroud)
auth-guard.ts
export class AuthService {
public user: Observable<firebase.User>;
public userDetails: firebase.User = null;
public userProfileRef: firebase.database.Reference;
userData: any[] = [];
constructor(private _firebaseAuth: AngularFireAuth, private router: Router) {
this.user = _firebaseAuth.authState;
this.userProfileRef = firebase.database().ref('/userProfile');
this.user.subscribe(
(user) => {
if (user) {
this.userDetails = user;
} else {
this.userDetails = null;
}
}
);
}
isLoggedIn() {
if (this.userDetails == null) {
return false;
} else {
return true;
}
}
doSignOut() {
this._firebaseAuth.auth.signOut()
.then((res) => this.router.navigate(['/auth/login']));
}
}
Run Code Online (Sandbox Code Playgroud)
is-logged-guard.ts - 我知道这是问题所在。我将如何修复它?
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) { }
canActivate() {
return this.auth.user.take(1).map(authState => !!authState).do(authenticated => { new Promise<boolean>( (resolve, reject) => {
if (!authenticated) {
this.router.navigate(['auth/sigin']);
return resolve(false);
} else {
return resolve(true);
}
}
}
Run Code Online (Sandbox Code Playgroud)
app-routing.module.ts
@Injectable()
export class IsLoggedGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) { }
canActivate() {
return !this.auth.isLoggedIn();
}
}
Run Code Online (Sandbox Code Playgroud)
没问题。身份验证保护保护仪表板免受未经身份验证的用户的攻击,并将他们重定向到身份验证页面(即登录页面)。
没问题。如果经过身份验证的用户通过 localhost:4200 或 localhost:4200/#/dashboard 或 localhost:4200/#/ 或 localhost:4200/#/RANDOM_INVALID_URL 访问仪表板,则一切正常。守卫还将阻止已经在仪表板内的经过身份验证的用户访问身份验证页面。
问题。如果经过身份验证的用户通过 localhost:4200/#/auth 或 localhost:4200/#/auth/signin 访问仪表板,则守卫将无法保护用户并将用户重定向到仪表板主页。(即 John 已经登录并打开一个新的 Chrome 选项卡,并输入 localhost:4200/#/auth 守卫不会阻止他访问它)。如果 John 已经通过身份验证,我该如何修复我的警卫以阻止他访问身份验证页面?
您应该像这样更改 IsLoggedGuard:
@Injectable()
export class IsLoggedGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) { }
canActivate() {
return this.auth.user
.take(1)
.map(authState => {
if (authState) {
//user is already loggedin
//route the user to Dashboard page
//Or a page where you want the app to naviagte
this.router.navigate("dashboard route");
//dont show the Login page
return false;
} else {
//user is not loggedin
return true;
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
您看到了这个问题,因为当您在浏览器中输入“localhost:4200/#/auth” url 时,您的AuthGuard.user.subscribe[ie in the constructor this.user.subscribe(] 在IsLoggedGuard's canActivate()执行时可能尚未发出任何值[ie AuthService.isLoggedIn() 可能会返回false因为订阅回调可能尚未执行(填充 userDetails)]。
让我知道它是否能解决您的问题。
可能有更好的方法来实现您的 AuthService 以及使用 AuthService 的 Guard。如果您想要更好的代码,请告诉我。
编辑 - 另一种编写 AuthService 的方法
让我们像这样更改 AuthService:
export class AuthService {
//NOTE: I AM JUST SHOWING TWO THINGS - isUserLoggedIn AND userDetails
//FROM THIS CODE YOU WILL GET AN IDEA HOW TO WRITE OTHER PROPERTIES WHICH ARE RELEVANT FOR YOUR APP
//This will be used as a source for various observables
private _authState$: Observable<any>;
//Have an observable which will tell if user is loggedin or not
isUserLoggedIn$: Observable<boolean>;
userDetails$: Observable<firebase.User>;
public userProfileRef: firebase.database.Reference;
constructor(private _firebaseAuth: AngularFireAuth, private router: Router) {
this.userProfileRef = firebase.database().ref('/userProfile');
this.setupObserables();
}
setupObserables() {
// this observable will broadcast the emited values to multiple subscribers [or composed/dependent observables]
this._authState$ = this._firebaseAuth.authState
.publishReplay(1)
.refCount();
// lets componse/derive different observables required by the consumer of this service
// This observable's emitted value will tell if user is logged in or not
this.isUserLoggedIn$ = this._authState$
.map(user => {
return user ? true : false;
});
// This observable's emited value will return the user's detail [NOTE If user is not logged in then the emitted value will be NULL
// i.e. userDetail is NULL; Your consumer of this observable should decide what to do with NULL/NOT NULL Value]
this.userDetails$ = this._authState$
.map(user => user);
}
doSignOut() {
this._firebaseAuth.auth.signOut()
.then((res) => this.router.navigate(['/auth/login']));
}
}
Run Code Online (Sandbox Code Playgroud)
现在让我们在 IsLoggedGuard 中使用更新的 AuthService:
@Injectable()
export class IsLoggedGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) { }
canActivate() {
return this.auth.isUserLoggedIn$
.take(1)
.map(isLoggedIn => {
if (isLoggedIn) {
//user is already loggedin
//route the user to Dashboard page
//Or a page where you want the app to naviagte
this.router.navigate("dashboard route");
//dont show the Login page
return false;
} else {
//user is not loggedin
return true;
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
现在让我们在 AuthGuard 中使用更新的 AuthService:
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) { }
canActivate() {
return this.auth.isUserLoggedIn$
.take(1)
.map(isLoggedIn => {
if (!isLoggedIn) {
//user isNOT loggedin
//route the user to login page
this.router.navigate(['auth/sigin']);
//dont show the next route
//lets fail the guard
return false;
} else {
//user is loggedin; pass the guard i.e. show the next route associated with this guard
return true;
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
现在假设一些组件(假设组件名称是UserComponent)您想要显示登录的用户详细信息:
....component decorator...
export class UserComponent implements OnInit {
userDetails$: Observable<User>;
constructor(private _authService: AuthService) {
this.userDetails$ = this._authService.userDetails$;
}
}
Run Code Online (Sandbox Code Playgroud)
像这样呈现 userDetails:
<div *ngIf="(userDetails$ | async) as userDetails">
<!-- Render your user details here -->
<!-- If userDetails is NULL then nothing will be rendered -->
</div>
Run Code Online (Sandbox Code Playgroud)
需要注意的事情-在这个更新的代码中,我们没有订阅任何可观察对象。请注意async,在组件模板中,这负责订阅/取消订阅使用的 observable。
希望它会给你一个方向/想法。让我们尽可能地“反应式”而不是“势在必行”..:)
注意:我已经在 rxjs6 中测试了等效代码。看起来您正在使用 rxjs5,因此我已根据 rxjs5 调整了发布的代码。希望它会起作用。
| 归档时间: |
|
| 查看次数: |
2426 次 |
| 最近记录: |