我已经设置了一个带有firebase电子邮件和密码登录的身份验证保护,问题是它会自动触发到指定组件的路由
我已经实现了身份验证保护并将其设置在正确的模块提供程序中(因为我的应用程序中有许多提供程序。这是我的身份验证服务:
import { Injectable } from '@angular/core';
import { Router, Route ,CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, CanActivateChild, CanLoad } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { SimpleAuthService } from './simple-auth.service';
@Injectable()
export class AuthGuard implements CanActivate, CanActivateChild, CanLoad {
constructor(private authService: SimpleAuthService) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
const url: string = state.url;
return this.checkLogin(url);
}
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return this.canActivate(route, state);
}
canLoad(route: Route): Observable<boolean> {
const url: string = route.path;
return this.checkLogin(url);
}
checkLogin(url: string): Observable<boolean> {
return this.authService.isLoggedIn(url);
}
}
这是我注入它的组件类(登录组件)
import { Component, OnInit, ElementRef } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { SimpleAuthService } from '../../core/simple-auth.service';
declare var $: any;
@Component({
selector: 'app-login-cmp',
templateUrl: './login.component.html'
})
export class LoginComponent implements OnInit {
private toggleButton: any;
private sidebarVisible: boolean;
private nativeElement: Node;
private email ='[email protected]'
private password ='useruser';
constructor(private element: ElementRef, public authService: SimpleAuthService,
private router: Router, private route: ActivatedRoute) {
if (this.authService.login(this.email,this.password)) {
this.router.navigate(['dashboard']);
} else {
this.nativeElement = element.nativeElement;
this.sidebarVisible = false;
}
}
ngOnInit() {
this.login(this.email, this.password);
var navbar : HTMLElement = this.element.nativeElement;
this.toggleButton = navbar.getElementsByClassName('navbar-toggle')[0];
setTimeout(function() {
// after 1000 ms we add the class animated to the login/register card
$('.card').removeClass('card-hidden');
}, 700);
}
sidebarToggle() {
var toggleButton = this.toggleButton;
var body = document.getElementsByTagName('body')[0];
var sidebar = document.getElementsByClassName('navbar-collapse')[0];
if (this.sidebarVisible == false) {
setTimeout(function() {
toggleButton.classList.add('toggled');
}, 500);
body.classList.add('nav-open');
this.sidebarVisible = true;
} else {
this.toggleButton.classList.remove('toggled');
this.sidebarVisible = false;
body.classList.remove('nav-open');
}
}
login(username: string, password: string): void {
this.authService.login(username, password).then(_ => {
const redirectUrl: string = this.authService.redirectUrl || 'dashboard';
this.router.navigate([redirectUrl]);
});
}
}
这是我使用firebase进行的身份验证服务
import { Injectable } from '@angular/core';
import { Router, Route ,CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, CanActivateChild, CanLoad } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { AngularFireAuth } from 'angularfire2/auth';
import { User, UserCredential } from '@firebase/auth-types';
import { take, map, tap } from 'rxjs/operators';
@Injectable()
export class SimpleAuthService {
user: Observable<User>;
redirectUrl: string;
constructor(private afAuth: AngularFireAuth, private router: Router) {
this.user = this.afAuth.authState;
}
getUser(): Observable<User> {
return this.user.pipe(take(1));
}
isLoggedIn(redirectUrl: string): Observable<boolean> {
return this.user.pipe(
take(1),
map(authState => !!authState),
tap(authenticated => {
if (!authenticated) {
this.redirectUrl = redirectUrl;
this.router.navigate(['/']);
}
})
);
}
login(username: string, password: string): Promise<UserCredential> {
return this.afAuth.auth.signInWithEmailAndPassword(username, password);
}
logout(): Promise<boolean> {
return this.afAuth.auth.signOut().then(() => this.router.navigate(['/login']));
}
}
你知道我弄错了吗?
基本问题是你的login()
方法是异步的,但是你试图检查结果,好像它是一个同步方法。此外,login()
甚至没有返回任何目前void
,所以没有任何结果可以检查。无论哪种方式,即使结果作为Promise<T>
返回,您也需要使用then()
来访问结果/成功,并使用catch()
来相应地处理组件中的错误。您根本无法在if()
语句中检查结果。在基本级别,如果您尝试检查在if语句中返回Promise<T>
的函数,则无论是否在几毫秒之后触发catch()
,它都将始终是真实的。
function login(): Promise<boolean> {
return Promise.resolve(true);
}
if(login()) {} // this is always true regardless of `catch()` is triggered sometime in the future
使用angularfire2,您可以实时跟踪用户的身份验证状态,作为Observable<User>
,可以在canActivate()
等方法中使用。以下是一种方法,可以在auth服务中公开Observable<User>
,可用于检查登录状态,获取当前用户,甚至可以在模板中使用async
管道显示类似用户头像的内容。有一些RxJS运算符,如tap
,take
和map
,可以帮助避免不必要地保持订阅活跃。使用这些方法主要返回Observable<T>
,您可以在其他服务或组件中另外管道其他运算符/操作以充分利用RxJS。
认证服务:
import { AngularFireAuth } from 'angularfire2/auth';
import { User, UserCredential } from '@firebase/auth-types';
@Injectable()
export class AuthService {
user: Observable<User>;
redirectUrl: string;
constructor(private afAuth: AngularFireAuth, private router: Router) {
this.user = this.afAuth.authState;
}
getUser(): Observable<User> {
return this.user.pipe(take(1));
}
isLoggedIn(redirectUrl: string): Observable<boolean> {
return this.user.pipe(
take(1),
map(authState => !!authState),
tap(authenticated => {
if (!authenticated) {
this.redirectUrl = redirectUrl;
this.router.navigate(['/login']);
}
})
);
}
login(username: string, password: string): Promise<UserCredential> {
return this.afAuth.auth.signInWithEmailAndPassword(email, password);
}
logout(): Promise<boolean> {
return this.afAuth.auth.signOut().then(() => this.router.navigate(['/login']));
}
}
Auth Guard:
@Injectable()
export class AuthGuard implements CanActivate, CanActivateChild, CanLoad {
constructor(private authService: AuthService) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
const url: string = state.url;
return this.checkLogin(url);
}
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return this.canActivate(route, state);
}
canLoad(route: Route): Observable<boolean> {
const url: string = route.path;
return this.checkLogin(url);
}
checkLogin(url: string): Observable<boolean> {
return this.authService.isLoggedIn(url);
}
}
零件:
export class LoginComponent implements OnInit {
constructor(private router: Router, public authService: AuthService) { }
ngOnInit() {
this.login(this.email, this.password);
}
login(username: string, password: string): void {
this.authService.login(username, password).then(_ => {
const redirectUrl: string = this.authService.redirectUrl || '/some-default-route';
this.router.navigate([redirectUrl]);
});
}
}
总体建议,您将希望为组件之间的通信提供更好的服务。您正在大量使用JavaScript操作与JavaScript和jQuery,这违背了Angular的目的,并且可能会导致问题,因为元素在您期望由于组件生命周期和渲染时将无法使用。使用服务和RxJS,您可以通过指令ngClass设置CSS类。查看有关Parent and children communicate via a service的文档,了解组件如何在基本级别进行通信的示例。如果它是你需要的Bootstrap,你应该考虑基于Angular的Bootstrap组件/库,这些组件/库挂钩到Angular组件生命周期并且不依赖于jQuery。
更新:
根据您提供的更新代码,您仍在尝试使用构造函数中的login()
语句检查异步Promise if
的成功。这将始终导致重定向,因为login()
正在返回一个承诺,这将是真正的价值。请尝试在then()
中使用catch()
/ LoginComponent
返回承诺,以响应Firebase的signInWithEmailAndPassword()
的成功/错误:
this.authService.login(this.email, this.password)
.then(result => this.router.navigate(['dashboard']))
.catch(err => {
this.nativeElement = element.nativeElement;
this.sidebarVisible = false;
});
希望这有帮助!