first commit

This commit is contained in:
Yangtao
2025-11-18 17:48:20 +08:00
commit 6e56cab848
196 changed files with 65809 additions and 0 deletions

11
pkg/secure/auth.go Normal file
View File

@ -0,0 +1,11 @@
package secure
const (
HeaderScopeCode = "X-SCOPE"
HeaderNonce = "X-NONCE"
HeaderSign = "X-S-SIGN"
TypeResource = "RESOURCE" // 资源权限
TypeInterface = "INTERFACE" // 接口权限
TypeData = "DATA" // 数据权限
)

86
pkg/secure/jwt.go Normal file
View File

@ -0,0 +1,86 @@
package secure
import (
"crypto/ecdsa"
"strings"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/google/uuid"
)
type Claims struct {
Username string `json:"un,omitempty"`
Nickname string `json:"nn,omitempty"`
ExtID string `json:"ei,omitempty"`
jwt.RegisteredClaims
}
func (c Claims) NeedRefresh(d time.Duration) bool {
return c.ExpiresAt.Before(time.Now().Add(d))
}
func GenerateToken(iss, uid, username, nickname string, exp, nbf, iat time.Time, aud []string, primaryKey string) (tokenStr string, e error) {
token := jwt.NewWithClaims(jwt.SigningMethodES256, &Claims{
Username: username,
Nickname: nickname,
RegisteredClaims: jwt.RegisteredClaims{
Issuer: iss, // 令牌发行者
Subject: uid, // 统一用户ID
Audience: aud, // 受众
ExpiresAt: &jwt.NumericDate{Time: exp}, // 过期时间
NotBefore: &jwt.NumericDate{Time: nbf}, // 启用时间
IssuedAt: &jwt.NumericDate{Time: iat}, // 发布时间
ID: JwtID(), // jwt ID
},
})
var ecdsaKey *ecdsa.PrivateKey
if ecdsaKey, e = jwt.ParseECPrivateKeyFromPEM([]byte(primaryKey)); e != nil {
panic(e)
}
tokenStr, e = token.SignedString(ecdsaKey)
return
}
func GenerateTokenWithEID(iss, uid, username, nickname, eid string, exp, nbf, iat time.Time, aud []string, primaryKey string) (tokenStr string, e error) {
token := jwt.NewWithClaims(jwt.SigningMethodES256, &Claims{
Username: username,
Nickname: nickname,
ExtID: eid,
RegisteredClaims: jwt.RegisteredClaims{
Issuer: iss, // 令牌发行者
Subject: uid, // 统一用户ID
Audience: aud, // 受众
ExpiresAt: &jwt.NumericDate{Time: exp}, // 过期时间
NotBefore: &jwt.NumericDate{Time: nbf}, // 启用时间
IssuedAt: &jwt.NumericDate{Time: iat}, // 发布时间
ID: JwtID(), // jwt ID
},
})
var ecdsaKey *ecdsa.PrivateKey
if ecdsaKey, e = jwt.ParseECPrivateKeyFromPEM([]byte(primaryKey)); e != nil {
panic(e)
}
tokenStr, e = token.SignedString(ecdsaKey)
return
}
func VerifyToken(tokenStr, publicKey string) (access bool, claims Claims, e error) {
var ecdsaKeyPub *ecdsa.PublicKey
if ecdsaKeyPub, e = jwt.ParseECPublicKeyFromPEM([]byte(publicKey)); e != nil {
return
}
var token *jwt.Token
if token, e = jwt.ParseWithClaims(tokenStr, &claims, func(token *jwt.Token) (interface{}, error) {
return ecdsaKeyPub, nil
}); e != nil {
return
}
access = token.Valid
return
}
func JwtID() string {
u4 := uuid.New()
return strings.ReplaceAll(u4.String(), "-", "")
}

12
pkg/secure/jwt_test.go Normal file
View File

@ -0,0 +1,12 @@
package secure
import (
"fmt"
"testing"
)
func TestVerifyToken(t *testing.T) {
ts := "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Inlhbmd0YW8iLCJuaWNrbmFtZSI6IuadqOeEmCIsImlzcyI6InpreHFncm91cC5jb20iLCJzdWIiOiJhZjBmNzM4OGM0MDk0MWQzYmU5NTdiYmExM2RkMzExYiIsImV4cCI6MTY4NDkxMjAwNCwibmJmIjoxNjg0ODI1NjA0LCJpYXQiOjE2ODQ4MjU2MDQsImp0aSI6IjkyNzIzMDM0NGE5MTQ0MTU4OTQyYWI4YmQ2MzkwMmQ2In0.58aFVo5FyTem4Fc2PZVBVEB-0DO2hhHuJ34ASGZQh1Cmd3peD5V5scWPdtx3wF3FAkXG_uE-o9smboGeuqscKQ"
gotAccess, gotClaims, err := VerifyToken(ts, "")
fmt.Printf("%v %v %v\n", gotAccess, gotClaims, err)
}

View File

@ -0,0 +1,9 @@
package secure
import "testing"
func Test_generatePasswd(t *testing.T) {
for i := 0; i < 20; i++ {
println(GeneratePasswd("advance", 16))
}
}

71
pkg/secure/tool.go Normal file
View File

@ -0,0 +1,71 @@
package secure
import (
"crypto/ecdsa"
"crypto/elliptic"
randcrypto "crypto/rand"
"crypto/x509"
"encoding/pem"
"fmt"
"math/rand"
"time"
)
type PassLevel string
const (
High PassLevel = "advance"
Mid PassLevel = "mix"
Low PassLevel = "char"
Danger PassLevel = "num"
nUmStr = "0123456789"
charStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
specStr = "+=-@#~,.[]()!%^*$"
)
var (
r = rand.New(rand.NewSource(time.Now().UnixNano()))
)
func GeneratePasswd(level PassLevel, length int32) string {
var passwd = make([]byte, length, length)
var sourceStr string
switch level {
case Danger:
sourceStr = nUmStr
case Low:
sourceStr = charStr
case Mid:
sourceStr = fmt.Sprintf("%s%s", nUmStr, charStr)
case High:
sourceStr = fmt.Sprintf("%s%s%s", nUmStr, charStr, specStr)
default:
sourceStr = fmt.Sprintf("%s%s", nUmStr, charStr)
}
for i := range passwd {
index := r.Intn(len(sourceStr))
passwd[i] = sourceStr[index]
}
return string(passwd)
}
func GenerateECDSAKeyPem() (primaryKey, publicKey []byte, e error) {
var (
key *ecdsa.PrivateKey
sec []byte
pk []byte
)
if key, e = ecdsa.GenerateKey(elliptic.P256(), randcrypto.Reader); e != nil {
return
}
if sec, e = x509.MarshalECPrivateKey(key); e != nil {
return
}
if pk, e = x509.MarshalPKIXPublicKey(key.Public()); e != nil {
return
}
primaryKey = pem.EncodeToMemory(&pem.Block{Type: "ECD PRIVATE KEY", Bytes: sec})
publicKey = pem.EncodeToMemory(&pem.Block{Type: "ECD PUBLIC KEY", Bytes: pk})
return
}