Vlang:JWT

module main

import crypto.hmac
import crypto.sha256
import encoding.base64
import json
import x.json2
import time

// JWT header fixed to use HS256 algorithm
const header = base64.url_encode_str(json.encode({
  "alg":"HS256"
  "typ":"JWT"
}))

// Generate token
fn generate(secret string, payload map[string]Any) string {
  playload_64 := base64.url_encode_str(json.encode(payload))

  message := '${header}.${playload_64}'
  signature := hmac.new(secret.bytes(), message.bytes(), sha256.sum, 0)
  base64_signature := base64.url_encode_str(signature.bytestr())
  return '${header}.${playload_64}.${base64_signature}'
}

fn main() {
  secret := '46546456'

  payload := {
    // Standard Claims https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
    "iss": Any("your-app-name"),         // Issuer
    "sub": "user123",               // Subject (unique user identifier)
    "aud": ["api-service", "webapp"], // Audience (can be array or string)
    "exp": I64(time.now().add_days(30).unix()),  // Expiration Time (30 days from now)
    "nbf": I64(time.now().unix()),       // Not Before (valid immediately)
    "iat": I64(time.now().unix()),       // Issued At
    "jti": "unique-jwt-id-123",     // JWT ID (prevent replay attacks)

    // Custom Claims
    "name": "Jengro",               // User's name
    "roles": ["admin", "editor"],   // User roles
    "status": "active",             // User status
    "meta": {                       // Nested object
       "login_ip": "192.168.1.100",
       "device_id": "device-xyz"
     }
  }

  token := generate(secret, payload)
  // println(token)

  // verify(secret, token)
  bj := verify(secret, token)
  println(bj)
}

// Verify token
fn verify(secret string, token string) bool {
  // Verify token length
  parts := token.split('.')
  if parts.len != 3 {
      return false
  }

  // Verify Header

  // Verify signature
  message := '${parts[0]}.${parts[1]}'
  signature := hmac.new(secret.bytes(), message.bytes(), sha256.sum, 0)
  expected_sig := base64.url_encode_str(signature.bytestr())
  if parts[2] != expected_sig {
    return false
  }

  // Verify time validity
  // dump(parts[1])
  payload_json := base64.url_decode_str(parts[1])
  payload := json2.decode[Payload](payload_json.str()) or {return false}
  dump(payload)
  now := time.now().unix()
  if now > payload.exp || now < payload.nbf {
      return false
  }

  return true
}

struct Header {
    alg string
    typ string
}

struct Payload {
    // Standard claims
    iss string
    sub string
    aud []string
    exp i64
    nbf i64
    iat i64
    jti string
    // Custom claims
    name   string
    roles  []string
    status string
    meta   map[string]string
}

type F64 = f64
type I64 = i64
type Any = string
    | []string
    | int
    | []int
    | I64
    | []f64
    | F64
    | bool
    | time.Time
    | map[string]int
    | map[string]string
    | []map[string]string
    | []map[string]Any
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容