乐趣区

Deno-JWT-token-应用

视频演示:

https://www.bilibili.com/video/BV1BT4y1E7Nh/?p=12

一起来完成以下步骤:

  1. 引用之前的工程代码
  2. 创建员工信息 interface 和员工数组 array
  3. 生成 token
  4. 校验 token 是否正确
  5. 运行命令: deno run –allow-net –allow-read main.ts

import {Context} from "https://deno.land/x/oak/mod.ts";
import {key} from "../middlewares/key.ts";
// 引入 jwt 模块功能
import {makeJwt, setExpiration, Jose, Payload} from "https://deno.land/x/djwt/create.ts"
import employees from "../models/employees.ts";

// 获取工程目录方法
const {cwd} = Deno;
//jwt 头部
const header: Jose = {
    alg: "HS256",
    typ: "JWT",
}


/**
 * 定义 Controller
 */
class Controller {
    /**
     * 首页
     * @param ctx 
     */
    static async hello(ctx: any) {
        //cwd 获取当前工程目录 
        // 注意 ' !== `
        ctx.render(`${cwd()}/views/index.ejs`, {
            title: "Testing",
            data: {name: "Deepincoding"}
        });
    }

    // 游客
    static async guest(ctx: Context) {ctx.response.body = "Hi Guest";}


    // 获取 token
    static async token(ctx: Context) {
        // 获取员工信息
        const {value} = await ctx.request.body();
        console.log({value});
        // 检查员工是否存在
        const hadEmployee = employees.find(employee => {return employee.username === value.username && employee.password === value.password;});

        if (hadEmployee) {
            //JWT body 可以放任何你想放的内容
            const payload: Payload = {
                iss: hadEmployee.username,
                exp: setExpiration(new Date().getTime() + 60000),
            }
            // 生成 JWT
            const jwt = makeJwt({key, header, payload});

            ctx.response.status = 200;
            // 返回
            ctx.response.body = {
                id: hadEmployee.id,
                username: hadEmployee.username,
                jwt,
            }
        } else {
            ctx.response.status = 422;
            // 返回提示信息
            ctx.response.body = {message: 'Invalid username or password'};
        }

    }
    // 需要 token 才能访问 admin
    static async admin(ctx: Context) {ctx.response.body = "Hi Admin";}

}

// 导出 Controller
export default Controller;

middlewares/authMiddleware.ts



import {Context} from "https://deno.land/x/oak/mod.ts";
import {validateJwt} from "https://deno.land/x/djwt/validate.ts"
import {key} from "./key.ts";

// 定义 authMiddleware 检查 token 有效性
const authMiddleware = async (ctx: Context, next: any) => {

    //token 放在 header 里面传过来
    const headers: Headers = await ctx.request.headers;
    
    const authorization = headers.get('Authorization')
    // 传过来的 token 是否以 bearer 开头 + 空格 
    if (!authorization || !authorization.split(' ')[1] ) {
      ctx.response.status = 401;
      return;
    }
    const jwt = authorization.split(' ')[1];
    // 校验 token
    const isValidateJwt = await validateJwt(jwt, key);
  
    // 如果 token 正确, 程序继续往下走,否则返回 401
    if (isValidateJwt.isValid) {await next();
      return;
    }
    ctx.response.status = 401;
    ctx.response.body = {message: 'Invalid jwt token'};
}

export default authMiddleware;

models/employee.ts


// 定义 interface
export interface Employee{
    id: string,
    username: string,
    password: string
}

// 初始化员工列表
const employees: Array<Employee> =[
    { 
        id: "1",
        username: "michael",
        password: "123456"
    },
    {
        id: "2",
        username: "alex",
        password: "654321"
    }
]
// 导出
export default employees;

routers/router.ts



// 引入 Router
import {Router} from "https://deno.land/x/oak/mod.ts";
// 引入自定义 Controller
import Controller from "../controllers/Controller.ts";
import authMiddleware from "../middlewares/authMiddleware.ts";

// 创建 router
const router = new Router();

// 首页 uri
router.get("/",Controller.hello);

// 不需要 token 可以访问 guest
router.get("/guest",Controller.guest);
// 根据用户名和密码获取 token
router.post("/token",Controller.token);
// 这里加上 token 校验的方法
router.get("/admin",authMiddleware,Controller.admin);


// 导出 router
export default router;

main.ts


// 引入 Application
import {Application} from "https://deno.land/x/oak/mod.ts"
// 引入页面渲染模块
import {viewEngine,engineFactory,adapterFactory} from "https://deno.land/x/view_engine/mod.ts";
// 引入 router
import router from "./routers/router.ts";

// 获取页面引擎
const ejsEngine = engineFactory.getEjsEngine();
// 获取 oak 适配器
const oakAdapter = adapterFactory.getOakAdapter();

// 创建 app
const app = new Application();

// 应用页面渲染引擎
app.use(viewEngine(oakAdapter,ejsEngine));
// 应用 router
app.use(router.routes());
app.use(router.allowedMethods());

//log 日志
console.log("Server Port 8000");

await app.listen({port: 8000})
退出移动版