Ionic4 JWT鉴权教程

转载:Ionic 4 JWT Authentication Tutorial: Using Angular HttpClient with Node & Express.js Server

本教程演示如何使用ionic4和angular7创建登陆注册module。

将学习如何使用HttpClient发生Post请求到使用Node+Express.js创建的鉴权后台,使用RxJS Observable跟踪授权状态;

如何使用Ionic Storage module保存Express.js 返回的JWT信息,如token、过期时间等;

开始之前,需要确定Node.js和NPM安装到开发电脑上;

设置安装 Ionic CLI 4

npm install -g ionic

全局安装ionic一般需要管理员权限,win使用管理员权限的命令行,类linux使用sudo

创建Ionic 4 项目

命令行运行下面命令

ionic start ionic-auth-demo blank --type=angular

ionic4使用type指定前端框架为angular,后面可能会有vue,react,现在反正没有。ionic4的目标是不限制框架,甚至是原生js,jquery都可以用ionic创建混合移动app或者pwa

blank指定模板类型,这个模板只带一个叫home的页面,其他还有tabs。。。

如果你想指定其他cli还能干的事情,如安装cordova,安装免费Ionic Appflow SDK这些后面教程再讲。

等cli安装完依赖后,你就可以进入创建的目录,使用ionic serve运行体验app了,ionic serve会自动打开浏览器访问localhost:8100,如果愿意,加个-l,运行起来更酷哦

创建 Angular Module

modules是用来组织你的程序代码的。创建一个module封装鉴权功能的service和pages。

ionic generate module auth

运行上面命令将自动生成src/app/auth/auth.module.ts,修改代码如下:

import { NgModule } from '@angular/core';

import { CommonModule } from '@angular/common';

@NgModule({

  declarations: [],

  imports: [

    CommonModule

  ]

})

export class AuthModule { }

auth Module只需要引入CommonModule,这个angular内建模块包含angular基本的一些 directives、pipes如:ngif,decimalPipe等

还需要再我们的root application模块(src/app/app.module.ts)引入auth模块。打开src/app/app.module.ts,再导入数组中添加AuthModule:

import { AuthModule } from './auth/auth.module';

@NgModule({

  declarations: [AppComponent],

  entryComponents: [],

  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule,

    AuthModule

  ],

  providers: [

    StatusBar,

    SplashScreen,

    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }

  ],

  bootstrap: [AppComponent]

})

export class AppModule {}

再导入HttpClient,发送http请求,FormsModule表单,Ionic Storage module本地存储

导入HttpClient

HttpClient是angular官方http客户端,所有我们需要在基于angular的ionic里导入。打开src/app/auth/auth.module.ts导入如下:

import { NgModule } from '@angular/core';

import { CommonModule } from '@angular/common';

import { HttpClientModule } from '@angular/common/http';

@NgModule({

  declarations: [],

  imports: [

    CommonModule,

    HttpClientModule

  ]

})

export class AuthModule { }

设置表单模块

angular为表单提供了强大的api,如基于模板的表单和reactive表单,这里我们用基于模板的表单,添加src/app/auth/auth.module.ts如下:

import { NgModule } from '@angular/core';

import { CommonModule } from '@angular/common';

import { HttpClientModule } from '@angular/common/http';

import { FormsModule } from '@angular/forms';

@NgModule({

  declarations: [],

  imports: [

    CommonModule,

    HttpClientModule,

    FormsModule

  ]

})

export class AuthModule { }

设置存储模块

ionic team提供的存储模块可以在移动设备的浏览器本地存储,但是使用前必须先安装并引入

安装使用命令:

npm install --save @ionic/storage

写这教程的时候,版本是2.2.0.

import { NgModule } from '@angular/core';

import { CommonModule } from '@angular/common';

import { HttpClientModule } from '@angular/common/http';

import { FormsModule } from '@angular/forms';

import { IonicStorageModule } from '@ionic/storage';

@NgModule({

  declarations: [],

  imports: [

    CommonModule,

    HttpClientModule,

    FormsModule,

    IonicStorageModule.forRoot()

  ]

})

export class AuthModule { }

创建Angular鉴权服务

设置了所有需要的设置后,我们可以创建鉴权服务了,用来封装HttpClient与Express server的通讯,如下命令创建:

ionic generate interface auth/user

生成src/app/auth/user.ts,编辑如下:

export interface User {

    id: number;

    name: string;

    email: string;

    password: string;

}

注意:在命令行里的auth/前缀告诉CLI在auth module里生成。

还需要生成服务器响应的接口,

ionic generate interface auth/auth-response

export interface AuthResponse {

    user: {

        id: number,

        name: string,

        email: string

    } ,       

access_token: string,       

expires_in: number

}

具体怎么响应,在下一个部分,用Node+Express.js构建后台的时候再说。

ionic generate service auth/auth

生成auth服务,会产生两个文件:src/app/auth/auth.service.ts,src/app/auth/auth.service.spec.ts,多个spec的是用来自动化测试的,可以删除

import { Injectable } from '@angular/core';

import { HttpClient } from  '@angular/common/http';

import { tap } from  'rxjs/operators';

import { Observable, BehaviorSubject } from  'rxjs';

import { Storage } from  '@ionic/storage';

import { User } from  './user';

import { AuthResponse } from  './auth-response';

定义变量

AUTH_SERVER_ADDRESS: string = 'http://localhost:3000';authSubject = new BehaviorSubject(false);

AUTH_SERVER_ADDRESS是后台地址,authSubject是用来订阅鉴权状态的Observable类型变量。

下一步构造函数中注入HttpClient和Storage

constructor(private httpClient: HttpClient, private storage: Storage) { }

使用HttpClient发送Post请求

register(user: User): Observable {

    return this.httpClient.post(`${this.AUTH_SERVER_ADDRESS}/register`, user).pipe(

      tap(async (res:  AuthResponse ) => {

        if (res.user) {

          await this.storage.set("ACCESS_TOKEN", res.access_token);

          await this.storage.set("EXPIRES_IN", res.expires_in);

          this.authSubject.next(true);

        }

      })

    );

  }

login(user: User): Observable {

    return this.httpClient.post(`${this.AUTH_SERVER_ADDRESS}/login`, user).pipe(

      tap(async (res: AuthResponse) => {

        if (res.user) {

          await this.storage.set("ACCESS_TOKEN", res.access_token);

          await this.storage.set("EXPIRES_IN", res.expires_in);

          this.authSubject.next(true);

        }

      })

    );

  }

async logout() {

    await this.storage.remove("ACCESS_TOKEN");

    await this.storage.remove("EXPIRES_IN");

    this.authSubject.next(false);

  }

获取鉴权状态

最后添加isLoggedIn()方法用来检查用户登陆与否

isLoggedIn() {

    return this.authSubject.asObservable();

  }

创建Ionic Pages

创建页面使用如下命令:

ionic generate page auth/register

命令会自动更新src/app/app-routing.module.ts,添加如下路由:

{ path: 'register', loadChildren: './auth/register/register.module#RegisterPageModule' },

意思是可以直接通过http://localhost:8100/register访问注册页面

打开src/app/auth/register/register.page.ts文件,注入Authservice和Router

import { Component, OnInit } from '@angular/core';

import { Router } from  "@angular/router";

import { AuthService } from '../auth.service';

@Component({

  selector: 'app-register',

  templateUrl: './register.page.html',

  styleUrls: ['./register.page.scss'],

})

export class RegisterPage implements OnInit {

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

  ngOnInit() {

  }

}

添加register()方法

register(form) {

    this.authService.register(form.value).subscribe((res) => {

      this.router.navigateByUrl('home');

    });

  }

修改src/auth/register/register.page.html页面:

Create your account!

Register

编辑src/auth/register/register.page.scss,自定义UI:

ion-item{--background:#3880ff;--color:#fff;}ion-button{--background:#062f77;}

登陆页面略,详见:Ionic 4 Forms Tutorial: Login & Register UI Example with Theming

创建并运行后台服务

创建express-auth-demo文件夹,命令行进入当前文件夹后,运行

npm init -y

初始化package.json文件,然后运行下面命令添加依赖:

npm install --save express body-parser sqlite3 bcryptjs jsonwebtoken cors

然后创建index.js文件,添加如下代码:

"use strict";

const express=require('express');

const bodyParser=require('body-parser');

const cors=require('cors');

const sqlite3=require('sqlite3').verbose();

const jwt=require('jsonwebtoken');

const bcrypt=require('bcryptjs');

const SECRET_KEY="secretkey23456";

const app=express();

constrouter=express.Router();app.use(cors())router.use(bodyParser.urlencoded({extended:false}));router.use(bodyParser.json());constdatabase=newsqlite3.Database("./my.db");constcreateUsersTable=()=>{constsqlQuery=`

        CREATE TABLE IF NOT EXISTS users (

        id integer PRIMARY KEY,

        name text,

        email text UNIQUE,

        password text)`;returndatabase.run(sqlQuery);}constfindUserByEmail=(email,cb)=>{returndatabase.get(`SELECT * FROM users WHERE email = ?`,[email],(err,row)=>{cb(err,row)});}constcreateUser=(user,cb)=>{returndatabase.run('INSERT INTO users (name, email, password) VALUES (?,?,?)',user,(err)=>{cb(err)});}createUsersTable();router.get('/',(req,res)=>{res.status(200).send('This is an authentication server');});router.post('/register',(req,res)=>{constname=req.body.name;constemail=req.body.email;console.log(req.body);constpassword=bcrypt.hashSync(req.body.password);createUser([name,email,password],(err)=>{if(err)returnres.status(500).send("Server error!");findUserByEmail(email,(err,user)=>{if(err)returnres.status(500).send('Server error!');constexpiresIn=24*60*60;constaccessToken=jwt.sign({id:user.id},SECRET_KEY,{expiresIn:expiresIn});res.status(200).send({"user":user,"access_token":accessToken,"expires_in":expiresIn});});});});router.post('/login',(req,res)=>{constemail=req.body.email;constpassword=req.body.password;findUserByEmail(email,(err,user)=>{if(err)returnres.status(500).send('Server error!');if(!user)returnres.status(404).send('User not found!');constresult=bcrypt.compareSync(password,user.password);if(!result)returnres.status(401).send('Password not valid!');constexpiresIn=24*60*60;constaccessToken=jwt.sign({id:user.id},SECRET_KEY,{expiresIn:expiresIn});res.status(200).send({"user":user,"access_token":accessToken,"expires_in":expiresIn});});});app.use(router);constport=process.env.PORT||3000;constserver=app.listen(port,()=>{console.log('Server listening at http://localhost:'+port);});


具体代码意思,查看Node Express JWT Authentication — jsonwebtoken and bcryptjs

编辑package.json,添加如下:

"scripts": {

    "start": "node index.js"

},

运行 npm start启动后台服务

你可能感兴趣的:(Ionic4 JWT鉴权教程)