Angular 路由守卫(登入篇)

经过了昨天的介绍,今天就来看看使用登入范例罗

今天的登入资料依然是使用 FakeStoreAPI

登入画面

这里就做个简单的验证,没填值就不能按按钮

<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <div>
    <label for="">userName:</label>
    <input type="text" formControlName="username" required />
  </div>
  <div>
    <label for="">passWord:</label>
    <input type="password" formControlName="password" required />
  </div>
  <button [disabled]="!form.valid">Login</button>
</form>
import { Component } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { Router } from "@angular/router";
import { AuthService } from "../auth.service";

@Component({
  selector: "app-login",
  templateUrl: "./login.component.html",
  styleUrls: ["./login.component.css"],
})
export class LoginComponent {
  form: FormGroup = new FormGroup({
    username: new FormControl(""),
    password: new FormControl(""),
  });

  constructor(private router: Router, private authService: AuthService) {}

  onSubmit() {
    const { username, password } = this.form.value;
    this.authService.login(username, password).subscribe((res: any) => {
      if (res.token) {
        // 登入成功後的跳转网址
        this.router.navigate([""]);
      } else {
        console.log("error", res);
      }
    });
  }
}

API Service

import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { tap } from "rxjs/operators";

@Injectable({
  providedIn: "root",
})
export class AuthService {
  setToken$: BehaviorSubject<string> = new BehaviorSubject("");
  constructor(private httpClient: HttpClient) {}
  login(username: string, password: string) {
    const url = `https://fakestoreapi.com/auth/login`;

    return this.httpClient
      .post(
        url,
        JSON.stringify({
          username,
          password,
        }),
        {
          headers: new HttpHeaders({
            "Content-Type": "application/json",
          }),
        }
      )
      .pipe(
        tap((res: any) => {
          this.setToken$.next(res.token);
        })
      );
  }
}

若是有成功得到 token 就装这状态记录在 setToken$


路由守卫 auth.guard.ts

import { Injectable } from "@angular/core";
import {
  CanActivate,
  ActivatedRouteSnapshot,
  RouterStateSnapshot,
  Router,
} from "@angular/router";
import { map, Observable } from "rxjs";
import { AuthService } from "./auth.service";

@Injectable({
  providedIn: "root",
})
export class AuthGuard implements CanActivate {
  constructor(private router: Router, public authService: AuthService) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | Promise<boolean> | boolean {
    return this.canEnter();
  }

  canActivateChild(): Observable<boolean> {
    return this.canEnter();
  }

  canEnter(): Observable<boolean> {
    // 这里提取刚刚记录的状态
    return this.authService.setToken$.pipe(
      map((isLogin) => {
        if (!isLogin) {
          this.router.navigate(["/", "login"]);
        }
        return !!isLogin;
      })
    );
  }
}

canEnter 订阅刚刚的 setToken$ 状态,若是没有 token 则导回 login 页


路由设定

import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { LoginComponent } from "./login/login.component";
import { AuthGuard } from "./auth.guard";
import { HomeComponent } from "./home/home.component";

const routes: Routes = [
  {
    path: "login",
    component: LoginComponent,
  },
  {
    path: "",
    component: HomeComponent,
    canActivate: [AuthGuard], //新增路由守卫
  },
  {
    path: "",
    pathMatch: "full",
    redirectTo: "/",
  },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}

今天的范例就放在这里罗
https://stackblitz.com/edit/angular-ivy-pwkhc4


<<:  延伸(1)-ML接入团队的原本开发生态 | ML#Day29

>>:  Day22 探讨Templates

29 - 有效的使用 Observability 的资料 (3) - 资料的生命周期管理

有效的使用 Observability 的资料 系列文章 (1/4) - 透过 Machine Le...

DAY30 - 完赛心得与下一步

第一次参加铁人赛,原本以为超前部署,开赛前两个星期就开始准备文章存档 本以为一定妥当的啦,没想到後面...

Day 30 - 每日产生观察名单

本篇重点 每日下载及更新Kbar资料 每日产生观察名单 结论 每日下载及更新Kbar资料 每天下载及...

JavaScript Arrow Function(箭头函式)

箭头函式 箭头函式功能与一般函式的用法大致差不多,不过写法却比一般函式还要简洁的多。 这里就直接来时...

Day 21 例外及堆叠的处理方式

大部分的处理器都有以下四种例外的类型,优先权由高至低排列: 1.非同步不可遮罩 2.同步精确 3.同...