新增 cls 包,提供 CloudLiteSync JWT 令牌校验与集成支持;包含 CLSService 结构体及相关方法,支持本地和远程 Token 校验。更新 go.mod 和 go.sum 文件以引入 jwt 库,添加 README.md 文档说明集成步骤。
This commit is contained in:
45
README.md
Normal file
45
README.md
Normal file
@ -0,0 +1,45 @@
|
||||
# 令牌集成帮助
|
||||
|
||||
## 快速集成
|
||||
|
||||
1. 安装依赖:
|
||||
```sh
|
||||
go get -u git.mazhangjing.com/corkine/cls-client
|
||||
```
|
||||
2. 在代码中引用:
|
||||
```go
|
||||
import "git.mazhangjing.com/corkine/cls-client/cls"
|
||||
```
|
||||
|
||||
CloudLiteSync 支持基于 JWT(JSON Web Token)的令牌鉴权机制,适用于微服务、Serverless、API 网关等多种场景。每个令牌项目拥有独立的 RSA 公私钥对,支持灵活的权限与用途隔离。
|
||||
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.mazhangjing.com/corkine/cls-client/cls"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 假设 publicKeyPEM、matchPurpose、remoteServer 已获取
|
||||
service := cls.NewCLSService(publicKeyPEM, matchPurpose, remoteServer)
|
||||
|
||||
// 1. 使用 JWT Token 进行本地校验
|
||||
claims, err := service.JwtAuth(tokenString)
|
||||
if err != nil {
|
||||
fmt.Println("JWT 校验失败:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("用户信息:", claims.Username, claims.Role)
|
||||
|
||||
// 2. 使用 quickKey 远程换取并校验 Token
|
||||
claims2, err := service.TokenAuth(quickKey)
|
||||
if err != nil {
|
||||
fmt.Println("Token 校验失败:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("用户信息:", claims2.Username, claims2.Role)
|
||||
}
|
||||
```
|
106
cls.go
Normal file
106
cls.go
Normal file
@ -0,0 +1,106 @@
|
||||
// Package cls 提供 CloudLiteSync JWT 令牌校验与集成支持。
|
||||
package cls
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
// CLSService 提供 JWT 校验与远程令牌获取服务。
|
||||
type CLSService struct {
|
||||
// PublicKey 用于校验 JWT 的 RSA 公钥
|
||||
PublicKey *rsa.PublicKey
|
||||
// MatchPurpose 期望的 purpose 字段,用于用途隔离
|
||||
MatchPurpose string
|
||||
// RemoteServer 远程令牌服务地址
|
||||
RemoteServer string
|
||||
}
|
||||
|
||||
// NewCLSService 创建一个新的 CLSService 实例。
|
||||
// publicKeyPEM 为 PEM 格式的 RSA 公钥,matchPurpose 为用途标识,remoteServer 为远程服务地址。
|
||||
func NewCLSService(publicKeyPEM, matchPurpose, remoteServer string) *CLSService {
|
||||
block, _ := pem.Decode([]byte(publicKeyPEM))
|
||||
if block == nil {
|
||||
panic("failed to parse PEM block")
|
||||
}
|
||||
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &CLSService{
|
||||
PublicKey: pub.(*rsa.PublicKey),
|
||||
MatchPurpose: matchPurpose,
|
||||
RemoteServer: remoteServer,
|
||||
}
|
||||
}
|
||||
|
||||
// JWTClaims 表示 JWT 令牌的自定义声明体。
|
||||
type JWTClaims struct {
|
||||
Username string `json:"username"` // 用户名
|
||||
Role string `json:"role"` // 角色
|
||||
Purpose string `json:"purpose"` // 用途标识
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// JwtAuth 使用 JWT Token 进行本地校验,返回用户声明信息。
|
||||
// tokenString 为待校验的 JWT 字符串。
|
||||
// 校验 purpose 字段与服务配置是否一致,并检查过期时间。
|
||||
func (s *CLSService) JwtAuth(tokenString string) (*JWTClaims, error) {
|
||||
token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
// 校验签名算法是否为 RSA
|
||||
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
return s.PublicKey, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse token: %w", err)
|
||||
}
|
||||
|
||||
if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid {
|
||||
if claims.Purpose != s.MatchPurpose {
|
||||
return nil, fmt.Errorf("purpose mismatch")
|
||||
}
|
||||
if claims.ExpiresAt.Before(time.Now()) {
|
||||
return nil, fmt.Errorf("token expired")
|
||||
}
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("invalid token")
|
||||
}
|
||||
|
||||
// TokenAuth 通过 quickKey 从远程服务获取并校验 JWT Token,返回用户声明信息。
|
||||
// key 为远程服务分发的 quickKey。
|
||||
func (s *CLSService) TokenAuth(key string) (*JWTClaims, error) {
|
||||
url := fmt.Sprintf("%s/s/%s", s.RemoteServer, key)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("remote server returned status %d", resp.StatusCode)
|
||||
}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var tokenClaims struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
err = json.Unmarshal(body, &tokenClaims)
|
||||
if err != nil || tokenClaims.Token == "" {
|
||||
return nil, err
|
||||
}
|
||||
return s.JwtAuth(tokenClaims.Token)
|
||||
}
|
5
go.mod
Normal file
5
go.mod
Normal file
@ -0,0 +1,5 @@
|
||||
module git.mazhangjing.com/corkine/cls-client
|
||||
|
||||
go 1.24.4
|
||||
|
||||
require github.com/golang-jwt/jwt/v5 v5.2.3
|
Reference in New Issue
Block a user