我遇到了一个有趣的问题,当用户尝试访问他们不应该访问的路由时,当我尝试重定向时,Angular Guard似乎什么也没做。
如您所见,我在整个过程中都放置了console.log调用,并且看到了我期望的消息,但是导航从未发生,并且最初请求的页面也像平常一样加载。这真的让我感到困惑-任何帮助将不胜感激!
警卫队
// angular dependencies
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
// rxjs utils
import { Observable } from 'rxjs';
import { take, map, tap } from 'rxjs/operators';
// service(s)
import { AuthService } from './services/auth/auth.service';
// interface(s)
import User from './interfaces/user.interface';
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(private _authService: AuthService, private _router: Router) { }
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
const url = state.url;
console.log('Auth Guard hit', { url: url });
return this._authService.user.pipe(
take(1),
map(user => {
console.log(user);
return !!user;
}),
tap(authenticated => {
console.log(`Authenticated: ${authenticated}`);
// not authenticated
if (!authenticated) {
// accessing sign in or sign up pages
if (['/login', '/register'].includes(url)) {
console.log('Allow through');
return true;
}
// accessing application
else {
console.log('Should bounce to login');
return this._router.createUrlTree(['/login']);
}
}
// authenticated
else {
// accessing sign in or sign up pages
if (['/login', '/register'].includes(url)) {
console.log('Should bounce to dashboard');
return this._router.createUrlTree(['/dashboard']);
}
// accessing application
else {
console.log('Allow through');
return true;
}
}
})
);
}
}
AuthService
// angular dependencies
import { Injectable } from '@angular/core';
// firebase dependencies
import { AngularFireAuth } from '@angular/fire/auth';
import { AngularFirestore } from '@angular/fire/firestore';
// RXJS helpers
import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
// interfaces
import User from '../../interfaces/user.interface';
@Injectable({ providedIn: 'root' })
export class AuthService {
public user: Observable<User> = null;
constructor(private _auth: AngularFireAuth, private _firestore: AngularFirestore) {
this.user = this._auth.authState.pipe(
switchMap(({ uid }) => {
if (uid) {
return this._firestore.doc(`users/${uid}`).valueChanges();
} else {
return of(null);
}
})
);
}
public async createAccount(email: string, password: string, forename: string, surname: string, relevantTags: string[] = []) {
// create the user in the auth system
let authUser;
try {
authUser = await this._auth.auth.createUserWithEmailAndPassword(email, password);
} catch (error) {
console.error('Failed to create user in auth system', { reason: error.message });
throw error;
}
// flesh out the user data
const data: User = {
uid: authUser.user.uid,
forename: forename,
surname: surname,
displayName: `${forename} ${surname}`,
roles: ['user'], // everyone has user role, can be promoted by admin as required
relevantTags: relevantTags,
emailVerified: false
};
// create the user in the database
try {
this._firestore.doc(`users/${data.uid}`).set(data);
} catch (error) {
console.error('Failed to create user in database', { reason: error.message });
throw error;
}
// attempt to send the initial verification email
try {
this.sendVerification();
} catch (error) {
console.warn('Failed to send verification email', { reason: error.message });
throw error;
}
}
public async signIn(email: string, password: string) {
// attempt to sign in
let result: firebase.auth.UserCredential;
try {
result = await this._auth.auth.signInWithEmailAndPassword(email, password);
} catch (error) {
console.error('Failed to log in', { reason: error.message });
throw error;
}
// store the user data for access by controllers
try {
this.user = this._firestore.doc<User>(`users/${result.user.uid}`).valueChanges();
} catch (error) {
console.error('Failed to set user on service', { reason: error.message });
this._auth.auth.signOut();
throw new Error('Failed to log in');
}
}
public async signOut() {
// attempt to sign out
try {
await this._auth.auth.signOut();
} catch (error) {
console.error('Failed to log out', { reason: error.message });
throw new Error('Failed to log out');
}
}
public async sendVerification() {
// attempt to send verification email
try {
this._auth.auth.currentUser.sendEmailVerification();
} catch (error) {
console.error('Failed to send verification', { reason: error.message });
throw new Error('Failed to send verification');
}
}
}
答案 0 :(得分:1)
Angular Guard应该以布尔值解析。因此,即使使用重定向,也不要使用tap运算符,而要使用map运算符并始终返回一个布尔值。尝试将代码更改为以下代码:
return this._authService.user.pipe(
take(1),
map(user => {
console.log(user);
return !!user;
}),
map(authenticated => {
console.log(`Authenticated: ${authenticated}`);
// not authenticated
if (!authenticated) {
// accessing sign in or sign up pages
if (['/login', '/register'].includes(url)) {
console.log('Allow through');
return true;
}
// accessing application
else {
console.log('Should bounce to login');
this._router.navigateByUrl('/login');
return false;
}
}
// authenticated
else {
// accessing sign in or sign up pages
if (['/login', '/register'].includes(url)) {
console.log('Should bounce to dashboard');
this._router.navigateByUrl('/dashboard');
return false;
}
// accessing application
else {
console.log('Allow through');
return true;
}
}
})
);
答案 1 :(得分:0)
最近我遇到了同样的问题,结果是我在重定向到的路由上设置了另一个防护。因此,请确保您在login