crypt jwt 签名验证 #45
This commit is contained in:
24
readme.md
24
readme.md
@ -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
37
src/ont/crypt.ts
Normal 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
34
src/ont/jwt.ts
Normal 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
|
||||
}
|
@ -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"
|
||||
|
@ -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("江苏", "苏州"),
|
||||
|
Reference in New Issue
Block a user