Gee*_*san 1 authentication angular-routing angular-services angular
我已经设置了一个带有 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);
}
}
Run Code Online (Sandbox Code Playgroud)
这是我注入它的组件类(登录组件):
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 ='user@dev.org'
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]);
});
}
}
Run Code Online (Sandbox Code Playgroud)
这是我使用 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']));
}
}
Run Code Online (Sandbox Code Playgroud)
你知道我在哪里犯了错误吗?
基本问题是您的login()方法是异步的,但您正在尝试检查结果,就好像它是同步方法一样。此外,login()当前甚至没有返回任何内容void,因此不会有任何结果需要检查。无论哪种方式,即使结果作为 返回Promise<T>,您也需要使用then()来访问结果/成功,并catch()在组件中相应地处理错误。您根本无法在这样的if()语句中检查结果。在基本层面上,如果你试图检查一个Promise<T>在 if 语句中返回 a 的函数,它总是真实的,无论是否catch()在几毫秒后被触发。
function login(): Promise<boolean> {
return Promise.resolve(true);
}
if(login()) {} // this is always true regardless of `catch()` is triggered sometime in the future
Run Code Online (Sandbox Code Playgroud)
使用 angularfire2,您可以实时跟踪用户的身份验证状态Observable<User>,可用于诸如canActivate(). 这是您可以采用的一种方法,它Observable<User>在 auth 服务中公开,可用于检查登录状态,获取当前用户,甚至在模板中使用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']));
}
}
Run Code Online (Sandbox Code Playgroud)
授权守卫:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
成分:
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]);
});
}
}
Run Code Online (Sandbox Code Playgroud)
总体建议,您将希望更好地利用服务进行组件之间的通信。您在 JavaScript 和 jQuery 中大量使用 DOM 操作,这违背了 Angular 的目的,并且可能会导致问题,因为由于组件生命周期和渲染,元素在您预期时不可用。使用服务和 RxJS,您可以通过指令ngClass设置 CSS 类。查看关于Parent 和 children 通过服务进行通信的文档,了解组件如何在基本级别进行通信的示例。如果它是您需要的 Bootstrap,您应该考虑基于 Angular 的 Bootstrap 组件/库,这些组件/库与 Angular 组件生命周期挂钩,并且不依赖于 jQuery。
更新:
根据您提供的更新代码,您仍在尝试login()使用if构造函数中的语句检查异步 Promise 是否成功。这将始终导致重定向,因为login()它会返回一个真实值的承诺。而是尝试在您返回的承诺上使用then()/来响应 Firebase 的成功/错误:catch()LoginComponentsignInWithEmailAndPassword()
this.authService.login(this.email, this.password)
.then(result => this.router.navigate(['dashboard']))
.catch(err => {
this.nativeElement = element.nativeElement;
this.sidebarVisible = false;
});
Run Code Online (Sandbox Code Playgroud)
希望这有帮助!
| 归档时间: |
|
| 查看次数: |
1928 次 |
| 最近记录: |