crypt jwt 签名验证 #45

This commit is contained in:
728
2023-11-14 10:18:55 +08:00
parent 48d768bec9
commit 7b9ff1cd43
5 changed files with 101 additions and 12 deletions

View File

@ -5,20 +5,22 @@
* `src` 源代码 `source`
* `ont` 基础计算 `ontic`
- `base.ts` 进制转换
- `utc.ts` 时间格式
- `adm.ts` 行政区划
- `utc.ts` 时间格式 `Universal Time Convention`
- `crypt.ts` 签名验证 `cryptography`
- `jwt.ts` 身份验证 `JSON Web Token`
- `adm.ts` 行政区划 `administrative region`
- `json.ts` JSON数据声明
* `eid` 核心操作 `eidetic`
- `typ.ts` 数据类型声明
- `db.ts` 数据库初始化与数据操作类型声明
- `typ.ts` 数据类型声明 `type`
- `db.ts` 数据库初始化与数据操作类型声明 `database`
- `is.ts` 数据定义与检查
- `id.ts` 实体数据操作
- `usr.ts` 用户数据操作
- `soc.ts` 俱乐部数据操作
- `agd.ts` 活动数据操作
- `rec.ts` 记录数据操作
- `msg.ts` 文章数据操作
- `aut.ts` 权限数据操作
- `id.ts` 实体数据操作 `identity`
- `usr.ts` 用户数据操作 `user`
- `soc.ts` 俱乐部数据操作 `sociation` `social`
- `agd.ts` 活动数据操作 `agenda`
- `rec.ts` 记录数据操作 `record`
- `msg.ts` 文章数据操作 `message`
- `aut.ts` 权限数据操作 `author` `authority
* `pra` 业务操作 `praxic`
* `tst` 测试代码 `tests`

37
src/ont/crypt.ts Normal file
View File

@ -0,0 +1,37 @@
import { to_u8 } from "./base.ts"
const alg = {
name: "HMAC",
hash: "SHA-256",
}
export function key(
k: string | ArrayBuffer,
): Promise<CryptoKey> {
if (typeof k == "string") k = to_u8(k)
return crypto.subtle.importKey("raw", k, alg, false, ["sign", "verify"])
}
export function sign(
key: CryptoKey,
data: string,
) {
return crypto.subtle.sign(alg, key, to_u8(data))
}
export function verify(
key: CryptoKey,
data: string,
sig: Uint8Array,
) {
return crypto.subtle.verify(alg, key, sig, to_u8(data))
}
export async function digest(
data: string | ArrayBuffer,
nitr = 1
) {
if (typeof data == "string") data = to_u8(data)
for (let n = 0; n < nitr; ++n)
data = await crypto.subtle.digest(alg.hash, data)
return data
}

34
src/ont/jwt.ts Normal file
View File

@ -0,0 +1,34 @@
import type { Json } from "./json.ts"
import { key, sign, verify } from "./crypt.ts"
import { frm_base64, frm_u8, to_base64, to_u8 } from "./base.ts"
const jwk_json = "./jwk.json"
let jwk = await key(`${Date.now() * Math.random()}`)
export async function jwk_set(
k: string
) {
jwk = await key(k)
}
export function jwk_load(
) {
jwk_set(Deno.readTextFileSync(jwk_json))
}
export async function jwt_sign(
json: Json
): Promise<string> {
const p = to_base64(to_u8(JSON.stringify(json)))
const s = to_base64(await sign(jwk, p))
return `${p}.${s}`
}
export async function jwt_verify<
T extends Json
>(
jwt: string
): Promise<T | null> {
const [p, s] = jwt.split(".")
if (!jwk || !s) return null
const v = await verify(jwk, p, frm_base64(s))
return v ? JSON.parse(frm_u8(frm_base64(p))) : null
}

View File

@ -1 +1,2 @@
export { assertEquals } from "https://deno.land/std@0.203.0/assert/assert_equals.ts"
export { assertNotEquals } from "https://deno.land/std@0.203.0/assert/assert_not_equals.ts"

View File

@ -1,7 +1,8 @@
import { is_adm } from "../src/ont/adm.ts"
import { frm_base64, frm_hex, frm_u8, to_base64, to_hex, to_u8 } from "../src/ont/base.ts"
import { jwk_set, jwt_sign, jwt_verify } from "../src/ont/jwt.ts";
import { utc_dt } from "../src/ont/utc.ts"
import { assertEquals } from "./mod.test.ts"
import { assertEquals, assertNotEquals } from "./mod.test.ts"
Deno.test("base", () => {
const t = "this is a test 1234"
@ -28,6 +29,20 @@ Deno.test("utc", () => {
assertEquals("2023-04-17", utc_dt(utc, "padutc"))
})
Deno.test("jwt", async () => {
const json = { usr: 1001, nam: "用户名", utc: Date.now() }
assertEquals(null, await jwt_verify(""))
const token = await jwt_sign(json)
assertEquals([true, 2], [token.length > 0, token.split(".").length])
assertEquals(null, await jwt_verify(token.substring(1)))
assertEquals(json, await jwt_verify(token))
await jwk_set("anotherkey")
assertEquals(null, await jwt_verify(token))
const token2 = await jwt_sign(json)
assertNotEquals(token, token2)
assertEquals(json, await jwt_verify(token2))
})
Deno.test("adm", () => {
assertEquals([true, false, false, true], [
is_adm("江苏", "苏州"),