Seize the day

POST : Backend study

Deno oak 서버에서 JWT 인증하기

error_code.ts

export class ErrorCode extends Error {
    code: number
    
    constructor(message: string, code: number) {
        super(message)
        this.code = code
    }
}

export const kCodeMaintenance: number = 1
export const kCodeJwtAuth: number = 2

export function throwJwtError(message: string) {
    throw new ErrorCode("jwt auth error: " + message, kCodeJwtAuth)
}

verify_token.ts

import {encode as base64url_encode, decode as base64url_decode} from "https://deno.land/std@0.103.0/encoding/base64url.ts"
import {hmac as createHmac} from "https://deno.land/x/crypto@v0.10.0/hmac.ts"
import {throwJwtError} from "./error_code.ts"

const PRIVATE_SECRET: Uint8Array = new TextEncoder().encode("private secret")

/*
 *  JWT token 유효성을 검사하고, 데이타를 추출하여 리턴한다.
 *  예외가 발생하면 ErrorCode를 던진다.
 *  const [uid, muid, did] = verifyJwtToken(token)
 */
export function verifyJwtToken(token: string): [string, string, string] {
    if (token == null) {
        throwJwtError("empty token")
    }
    const [header, payload, signiture] = token.split('.')
    const value = new TextEncoder().encode(header + "." + payload)
    const hmacValue = createHmac('sha256', PRIVATE_SECRET, value)
    const signiture2 = base64url_encode(hmacValue)
    if (signiture !== signiture2) {
        throwJwtError("invalid signiture")
    }
    const payloadJson: string = new TextDecoder().decode(base64url_decode(payload))
    const payloadObj = JSON.parse(payloadJson)
    const exp = payloadObj.exp || null
    if (typeof exp != "number") {
        throwJwtError("invalid exp")
    }
            
    if (exp <= Math.floor(Date.now()/1000)) {
        throwJwtError("expired token")
    }
    
    const uid = payloadObj.uid || null
    if (uid == null) {
        throwJwtError("empty uid")
    }
        
    const muid = payloadObj.muid || ""
    const did = payloadObj.did || ""
    return [uid, muid, did]
}

// request: oak request
export function verifyJwtRequest(request: any): [string, string, string] {
    return verifyJwtToken(request.headers.get("json-web-token"))
}

routes.ts

import { Router } from "https://deno.land/x/oak/mod.ts"
import getHello from "./v1/hello.ts"
import getUser from "./v1/user.ts"

const router = new Router()

router
    .get("/lt/v1/hello", getHello)
    .post("/lt/v1/user", getUser)

export default router

server.ts

import { Application, Context } from "https://deno.land/x/oak/mod.ts"
import router from './routes.ts'

const errorHandler = async (ctx: Context, next: any) => {
    try {
      await next();
    } catch (err) {
      ctx.response.status = 200;
      ctx.response.body = { code: err.code || 500, message: err.message }
    }
}

const _404 = async (ctx: Context) => {
    ctx.response.status = 200;
    ctx.response.body = { code: 404, message: "404 Not Found!" }
}


const app = new Application()
const port = 8000
app.use(errorHandler);
app.use(router.routes())
app.use(router.allowedMethods())
app.use(_404)

console.log("running:  api server port: " + port);
await app.listen({ port: port });

 

v1/hello.ts

import { verifyJwtRequest } from "../verify_token.ts"

const getHello = async ({ request, response }: { request: any; response: any }) => {
    const [uid, muid, did] = verifyJwtRequest(request)
    
    console.log(uid + ":" + muid + ":" + did)

    //const body = await request.body()
    //const text: string = body.value
    response.body = { 
        message: 'Hello OK',
        uid: uid,
        muid: muid,
        did: did
    }
    response.status = 200
}

export default getHello
top

posted at

2021. 8. 10. 22:08


CONTENTS

Seize the day
BLOG main image
김대정의 앱 개발 노트와 사는 이야기
RSS 2.0Tattertools
공지
아카이브
최근 글 최근 댓글
카테고리 태그 구름사이트 링크