feat: 实现 argon2 哈希池、令牌与登录锁定计数
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
sessionTokenPrefix = "nst_"
|
||||
apiTokenPrefix = "nxm_"
|
||||
tokenRandomBytes = 32
|
||||
)
|
||||
|
||||
// SessionTokenService 生成与哈希端会话令牌。
|
||||
type SessionTokenService struct{}
|
||||
|
||||
// NewSessionTokens 创建会话令牌服务。
|
||||
func NewSessionTokens() *SessionTokenService {
|
||||
return &SessionTokenService{}
|
||||
}
|
||||
|
||||
// Issue 生成 nst_ + 32 字节随机数的 base64url;返回明文与 SHA-256。
|
||||
func (s *SessionTokenService) Issue(_ context.Context) (string, []byte, error) {
|
||||
return issuePrefixedToken(sessionTokenPrefix)
|
||||
}
|
||||
|
||||
// HashToken 对令牌做 SHA-256。
|
||||
func (s *SessionTokenService) HashToken(token string) []byte {
|
||||
sum := sha256.Sum256([]byte(token))
|
||||
return sum[:]
|
||||
}
|
||||
|
||||
// LooksLikeSessionToken 判断是否以 nst_ 开头。
|
||||
func (s *SessionTokenService) LooksLikeSessionToken(credential string) bool {
|
||||
return strings.HasPrefix(credential, sessionTokenPrefix)
|
||||
}
|
||||
|
||||
// APITokenService 生成与哈希 API 令牌。
|
||||
type APITokenService struct{}
|
||||
|
||||
// NewAPITokens 创建 API 令牌服务。
|
||||
func NewAPITokens() *APITokenService {
|
||||
return &APITokenService{}
|
||||
}
|
||||
|
||||
// Issue 生成 nxm_ + 32 字节随机数的 base64url;返回明文与 SHA-256。
|
||||
func (s *APITokenService) Issue(_ context.Context) (string, []byte, error) {
|
||||
return issuePrefixedToken(apiTokenPrefix)
|
||||
}
|
||||
|
||||
// HashToken 对令牌做 SHA-256。
|
||||
func (s *APITokenService) HashToken(token string) []byte {
|
||||
sum := sha256.Sum256([]byte(token))
|
||||
return sum[:]
|
||||
}
|
||||
|
||||
// LooksLikeAPIToken 判断是否以 nxm_ 开头。
|
||||
func (s *APITokenService) LooksLikeAPIToken(credential string) bool {
|
||||
return strings.HasPrefix(credential, apiTokenPrefix)
|
||||
}
|
||||
|
||||
// EqualHash 常量时间比较两个哈希。
|
||||
func EqualHash(a, b []byte) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
return subtle.ConstantTimeCompare(a, b) == 1
|
||||
}
|
||||
|
||||
func issuePrefixedToken(prefix string) (string, []byte, error) {
|
||||
raw := make([]byte, tokenRandomBytes)
|
||||
if _, err := rand.Read(raw); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
tok := prefix + base64.RawURLEncoding.EncodeToString(raw)
|
||||
sum := sha256.Sum256([]byte(tok))
|
||||
return tok, sum[:], nil
|
||||
}
|
||||
|
||||
var (
|
||||
_ SessionTokens = (*SessionTokenService)(nil)
|
||||
_ APITokens = (*APITokenService)(nil)
|
||||
)
|
||||
Reference in New Issue
Block a user