背景
最近在跟老师做项目的时候,需要处理这样一种情况: 当访问网站的某一个功能的时候需要先登录(认证)才能访问。
什么是路由守卫
路由守卫是一种机制,用于在导航到某个路由之前或之后执行一些代码。这可以帮助你控制导航的行为,比如检查用户是否有权限访问某个页面,确认用户是否已经登录,最常见的例子就是我们访问淘宝的东西,我们浏览器商品的时候不用进行登陆,而当我们看中某一种商品的需要点击购买的时候,点击购买的时候就需要我们进行登陆。
Angular路由守卫:
- CanActivate:
作用: 在导航到某个路由前执行,决定是否允许进入该路由。
使用场景: 检查用户是否有足够的权限访问该路由,或者是否已经登录。 - CanDeactivate:
作用: 在离开某个路由前执行,决定是否允许离开该路由。
使用场景: 提示用户保存未保存的更改,或者执行其他清理操作。 - Resolve:
作用: 在路由激活之前,先解析一些数据。
使用场景: 在加载组件之前,确保所有需要的数据都已加载。 - CanLoad:
作用: 在异步加载模块之前执行,决定是否允许加载该模块。
使用场景: 检查用户是否有权限加载某个懒加载的模块。
守卫返回一个值,以控制路由器的行为:
- true 导航过程会继续
- false 导航过程就会终止,且用户留在原地。
- UrlTree 取消当前导航,并开始导航到所返回的 UrlTree
canActivate:身份验证
新建 admin模块、新建 admin组件
ng generate module admin
ng generate component admin/admin
编辑配置 admin路由信息:
const routes: Routes = [
{
path: 'admin',
component: AdminComponent,
},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
编辑admin-component模版
<h2>admin</h2>
<nav>
<a>Dashboard</a>
<a>Manage Crises</a>
<a>Manage Heroes</a>
</nav>
添加守卫
添加一个login模块来认证用户信息和登陆
ng generate module login
创建守卫:
ng g g auth //这里我们选择CanActivate
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return true;
}
可以看出:返回值可以是三种类型的布尔值或 UrlTree。
使用只需要在路由配置文件中添加 CanActivate: [AuthGuard]
const Routes: Routes = [
{
path: 'admin',
component: AdminComponent,
canActivate: [AuthGuard]
}
];
此时,当守卫返回的时候true,可以访问admin组件
添加一个user服务来进行认证管理登陆状态
ng g service user
每次值更新会通知订阅值
loginUser$ = new ReplaySubject<boolean>(1);创建一个ReplaySubject,
import {Injectable} from '@angular/core';
import {ReplaySubject} from "rxjs";
@Injectable({
providedIn: 'root'
})
export class UserService {
loginUser$ = new ReplaySubject<boolean>(1);
login(): void {
this.loginUser$.next(true);
}
logout(): void {
this.loginUser$.next(false);
}
}
在守卫中使用userService
import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from '@angular/router';
import {Observable} from 'rxjs';
import {UserService} from "../service/user.service";
import {map} from "rxjs/operators";
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private userService: UserService,
private router: Router) {
}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.userService.loginUser$.pipe(map(v => {
if (v) {
return true;
} else {
return this.router.createUrlTree(['login'], {queryParams: {'redirectUrl': state.url}});
}
}));
}
}
新建login组件
ng g c login
编辑login-component.html
<p>{{message}}</p>
<p>
<button type="button" (click)="login()" *ngIf="!isLogin">Login</button>
<button type="button" (click)="logout()" *ngIf="isLogin">Logout</button>
</p>
编辑login-component.ts
message: string = ''; 登陆的信息
isLogin = false; 登陆的状态
redirectUrl = 'login';登陆成功之后的跳转地址
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, NavigationExtras, Router, RouterModule} from '@angular/router';
import {UserService} from "../../service/user.service";
import {filter} from "rxjs";
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
message: string = '';
isLogin = false;
redirectUrl = 'login';
constructor(public router: Router,
private route: ActivatedRoute,
private userService: UserService) {
}
ngOnInit(): void {
this.route.queryParams.pipe(filter((v => v.hasOwnProperty('redirectUrl')))).subscribe((v) => {
this.redirectUrl = v['redirectUrl'];
});
this.userService.loginUser$.subscribe((value) => {
this.isLogin = value;
this.message = this.isLogin ? 'login in' : 'login out';
if (this.isLogin) {
this.router.navigate([this.redirectUrl]);
}
});
}
login() {
this.message = 'Trying to log in ...';
this.userService.login();
}
logout() {
this.userService.logout();
}
}
配置login路由信息:
const routes: Routes = [
{
path: 'admin',
component: AdminComponent,
canActivate: [AuthGuard]
},
{
path: 'login',
component: LoginComponent
},
];
修改app-component模版
<div class="wrapper">
<h1 class="title">Angular Router</h1>
<nav>
<a routerLink="/admin" routerLinkActive="active">Admin</a>
<a routerLink="/login" routerLinkActive="active">Login</a>
</nav>
<router-outlet></router-outlet>
</div>
最总效果
总结
路由守卫是Angular中一个非常有用的功能,可以帮助我们控制用户在导航过程中的权限和访问限制
参考文章
https://angular.cn/guide/router-tutorial-toh#milestone-5-rout...
https://blog.csdn.net/yanyi24/article/details/115518763
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。