golang实现平台无关安全令牌(PASETO)的插件库paseto的使用
Golang实现平台无关安全令牌(PASETO)的插件库paseto的使用
什么是PASETO?
PASETO(Platform-Agnostic SEcurity TOkens)是一种用于安全无状态令牌的规范和参考实现。
PASETO与JWT的主要区别
与JSON Web Tokens(JWT)不同,PASETO只允许安全操作。JWT提供"算法灵活性",而PASETO提供"版本化协议"。
安装
要安装该库,请使用以下命令:
go get -u github.com/o1egl/paseto
使用示例
使用对称密钥创建令牌(本地模式)
symmetricKey := []byte("YELLOW SUBMARINE, BLACK WIZARDRY") // 必须是32字节
now := time.Now()
exp := now.Add(24 * time.Hour)
nbt := now
jsonToken := paseto.JSONToken{
Audience: "test",
Issuer: "test_service",
Jti: "123",
Subject: "test_subject",
IssuedAt: now,
Expiration: exp,
NotBefore: nbt,
}
// 添加自定义声明到令牌
jsonToken.Set("data", "this is a signed message")
footer := "some footer"
// 加密数据
token, err := paseto.Encrypt(symmetricKey, jsonToken, footer)
// token = "v2.local.E42A2iMY9SaZVzt-WkCi45_aebky4vbSUJsfG45OcanamwXwieieMjSjUkgsyZzlbYt82miN1xD-X0zEIhLK_RhWUPLZc9nC0shmkkkHS5Exj2zTpdNWhrC5KJRyUrI0cupc5qrctuREFLAvdCgwZBjh1QSgBX74V631fzl1IErGBgnt2LV1aij5W3hw9cXv4gtm_jSwsfee9HZcCE0sgUgAvklJCDO__8v_fTY7i_Regp5ZPa7h0X0m3yf0n4OXY9PRplunUpD9uEsXJ_MTF5gSFR3qE29eCHbJtRt0FFl81x-GCsQ9H9701TzEjGehCC6Bhw.c29tZSBmb290ZXI"
// 解密数据
var newJsonToken paseto.JSONToken
var newFooter string
err := paseto.Decrypt(token, symmetricKey, &newJsonToken, &newFooter)
使用非对称密钥创建令牌(公共模式)
b, _ := hex.DecodeString("b4cbfb43df4ce210727d953e4a713307fa19bb7d9f85041438d9e11b942a37741eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2")
privateKey := ed25519.PrivateKey(b)
b, _ = hex.DecodeString("1eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2")
publicKey := ed25519.PublicKey(b)
// 或者创建一个新的密钥对
// publicKey, privateKey, err := ed25519.GenerateKey(nil)
jsonToken := paseto.JSONToken{
Expiration: time.Now().Add(24 * time.Hour),
}
// 添加自定义声明到令牌
jsonToken.Set("data", "this is a signed message")
footer := "some footer"
// 签名数据
token, err := paseto.Sign(privateKey, jsonToken, footer)
// token = "v2.public.eyJkYXRhIjoidGhpcyBpcyBhIHNpZ25lZCBtZXNzYWdlIiwiZXhwIjoiMjAxOC0wMy0xMlQxOTowODo1NCswMTowMCJ9Ojv0uXlUNXSFhR88KXb568LheLRdeGy2oILR3uyOM_-b7r7i_fX8aljFYUiF-MRr5IRHMBcWPtM0fmn9SOd6Aw.c29tZSBmb290ZXI"
// 验证数据
var newJsonToken paseto.JSONToken
var newFooter string
err := paseto.Verify(token, publicKey, &newJsonToken, &newFooter)
使用Parse()函数解析所有支持的令牌版本
b, err := hex.DecodeString("2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0d0a4d494942496a414e42676b71686b6947397730424151454641414f43415138414d49494243674b43415145417878636e47724e4f6136426c41523458707050640d0a746146576946386f7279746c4b534d6a66446831314c687956627a4335416967556b706a457274394d7649482f46384d444a72324f39486b36594b454b574b6f0d0a72333566364b6853303679357a714f722b7a4e34312b39626a52365633322b527345776d5a737a3038375258764e41334e687242633264593647736e57336c5a0d0a34356f5341564a755639553667335a334a574138355972362b6350776134793755632f56726f6d7a674679627355656e33476f724254626a783142384f514a440d0a73652f4b6b6855433655693358384264514f473974523455454775742f6c39703970732b3661474d4c57694357495a54615456784d4f75653133596b777038740d0a3148467635747a6872493055635948687638464a6b315a6435386759464158634e797975737834346e6a6152594b595948646e6b4f6a486e33416b534c4d306b0d0a6c774944415141420d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d")
block, _ := pem.Decode(b)
rsaPubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
v1PublicKey := rsaPubInterface.(*rsa.PublicKey)
b, _ = hex.DecodeString("1eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2")
v2PublicKey := ed25519.PublicKey(b)
var payload JSONToken
var footer string
version, err := paseto.Parse(token, &payload, &footer, symmetricKey, map[paseto.Version]crypto.PublicKey{paseto.V1: v1PublicKey, paseto.V2: v2PublicKey})
支持的PASETO版本
版本2
版本2(规范推荐版本)完全支持。
版本1
版本1(兼容版本)完全支持。
性能基准
MacBook Pro (15-inch, 2018) CPU: 2,6 GHz Intel Core i7 RAM: 32 GB 2400 MHz DDR4 OS: macOS 10.14.6 GO: 1.13.7
$ go test -bench . -benchmem
Benchmark_V2_JSONToken_Encrypt-12 137578 8532 ns/op 4186 B/op 59 allocs/op
Benchmark_V2_JSONToken_Decrypt-12 139309 7970 ns/op 2048 B/op 63 allocs/op
Benchmark_V2_JSONToken_Sign-12 21598 55817 ns/op 4426 B/op 60 allocs/op
Benchmark_V2_JSONToken_Verify-12 8772 132142 ns/op 2528 B/op 64 allocs/op
Benchmark_V2_String_Encrypt-12 544958 2051 ns/op 1176 B/op 23 allocs/op
Benchmark_V2_String_Decrypt-12 1000000 1054 ns/op 568 B/op 18 allocs/op
Benchmark_V2_String_Sign-12 25144 47645 ns/op 1144 B/op 23 allocs/op
Benchmark_V2_String_Verify-12 9408 125524 ns/op 744 B/op 18 allocs/op
更多关于golang实现平台无关安全令牌(PASETO)的插件库paseto的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang实现平台无关安全令牌(PASETO)的插件库paseto的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用Go实现PASETO安全令牌
PASETO(Platform-Agnostic Security Tokens)是一种现代的安全令牌格式,相比JWT具有更简单的设计和更强的安全性。下面我将介绍如何在Go中使用paseto
库来实现PASETO令牌的创建和验证。
安装paseto库
首先安装Go的paseto实现库:
go get github.com/o1egl/paseto
基本用法示例
1. 创建v2版本的本地PASETO令牌
package main
import (
"fmt"
"time"
"github.com/o1egl/paseto"
"golang.org/x/crypto/chacha20poly1305"
)
func main() {
// 生成对称密钥(32字节)
symmetricKey := make([]byte, chacha20poly1305.KeySize)
if _, err := rand.Read(symmetricKey); err != nil {
panic(err)
}
// 创建PASETO v2对象
jsonToken := paseto.JSONToken{
Expiration: time.Now().Add(24 * time.Hour),
IssuedAt: time.Now(),
NotBefore: time.Now(),
Subject: "user123",
}
// 添加自定义声明
jsonToken.Set("data", "custom data")
// 创建token
token, err := paseto.NewV2().Encrypt(symmetricKey, jsonToken, nil)
if err != nil {
panic(err)
}
fmt.Println("Generated PASETO token:", token)
}
2. 验证v2本地PASETO令牌
func verifyToken(token string, symmetricKey []byte) {
var newJSONToken paseto.JSONToken
var newFooter string
// 验证token
err := paseto.NewV2().Decrypt(token, symmetricKey, &newJSONToken, &newFooter)
if err != nil {
fmt.Println("Token verification failed:", err)
return
}
// 检查过期时间
if time.Now().After(newJSONToken.Expiration) {
fmt.Println("Token expired")
return
}
fmt.Printf("Token verified! Subject: %s\n", newJSONToken.Subject)
fmt.Printf("Custom claim 'data': %s\n", newJSONToken.Get("data"))
}
3. 使用v2公共令牌(非对称加密)
func createPublicToken() {
// 生成RSA密钥对
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
publicKey := &privateKey.PublicKey
// 创建token
jsonToken := paseto.JSONToken{
Expiration: time.Now().Add(2 * time.Hour),
Issuer: "myapp",
Subject: "user456",
}
token, err := paseto.NewV2().Sign(privateKey, jsonToken, nil)
if err != nil {
panic(err)
}
fmt.Println("Public PASETO token:", token)
// 验证token
var verifiedJSONToken paseto.JSONToken
err = paseto.NewV2().Verify(token, publicKey, &verifiedJSONToken, nil)
if err != nil {
panic(err)
}
fmt.Printf("Verified token for user: %s\n", verifiedJSONToken.Subject)
}
最佳实践建议
-
密钥管理:
- 本地令牌使用强随机生成的密钥
- 公共令牌使用足够强度的RSA或Ed25519密钥
- 定期轮换密钥
-
令牌有效期:
- 设置合理的过期时间(通常几小时)
- 使用NotBefore防止令牌在发布后立即使用
-
自定义声明:
- 避免存储敏感信息
- 保持令牌尽可能小
-
错误处理:
- 区分不同类型的验证错误(过期、签名无效等)
- 记录但不泄露详细的错误信息给客户端
与JWT的比较
PASETO相比JWT有几个优势:
- 更简单的设计,减少了实现错误
- 强制使用现代加密算法
- 没有算法协商攻击的风险
- 更小的令牌大小
完整示例
package main
import (
"crypto/rand"
"crypto/rsa"
"fmt"
"time"
"github.com/o1egl/paseto"
"golang.org/x/crypto/chacha20poly1305"
)
func main() {
// 示例1: 本地令牌
fmt.Println("=== Local Token Example ===")
localTokenExample()
// 示例2: 公共令牌
fmt.Println("\n=== Public Token Example ===")
publicTokenExample()
}
func localTokenExample() {
// 生成32字节对称密钥
symmetricKey := make([]byte, chacha20poly1305.KeySize)
if _, err := rand.Read(symmetricKey); err != nil {
panic(err)
}
// 创建token
jsonToken := paseto.JSONToken{
Expiration: time.Now().Add(1 * time.Hour),
Issuer: "auth-service",
Subject: "user789",
}
jsonToken.Set("role", "admin")
token, err := paseto.NewV2().Encrypt(symmetricKey, jsonToken, nil)
if err != nil {
panic(err)
}
fmt.Println("Generated token:", token)
// 验证token
var verifiedToken paseto.JSONToken
err = paseto.NewV2().Decrypt(token, symmetricKey, &verifiedToken, nil)
if err != nil {
panic(err)
}
fmt.Printf("Verified token - Subject: %s, Role: %s\n",
verifiedToken.Subject, verifiedToken.Get("role"))
}
func publicTokenExample() {
// 生成RSA密钥对
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
publicKey := &privateKey.PublicKey
// 创建token
jsonToken := paseto.JSONToken{
Expiration: time.Now().Add(2 * time.Hour),
IssuedAt: time.Now(),
Subject: "service-account",
}
jsonToken.Set("scope", "read:data,write:data")
token, err := paseto.NewV2().Sign(privateKey, jsonToken, "key-id-123")
if err != nil {
panic(err)
}
fmt.Println("Generated public token:", token)
// 验证token
var verifiedToken paseto.JSONToken
var footer string
err = paseto.NewV2().Verify(token, publicKey, &verifiedToken, &footer)
if err != nil {
panic(err)
}
fmt.Printf("Verified token - Subject: %s, Scope: %s, Footer: %s\n",
verifiedToken.Subject, verifiedToken.Get("scope"), footer)
}
这个示例展示了PASETO的核心功能,包括本地和公共令牌的创建与验证。根据你的具体需求,可以调整令牌的有效期、声明内容和密钥管理策略。