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