feat(backend): bcrypt+jwt auth package and admin seeding

This commit is contained in:
2026-09-04 23:50:52 +08:00
parent c1761d0f3e
commit b224288dae
6 changed files with 168 additions and 1 deletions
+54
View File
@@ -0,0 +1,54 @@
package auth
import (
"crypto/subtle"
"errors"
"time"
"github.com/golang-jwt/jwt/v5"
"golang.org/x/crypto/bcrypt"
)
var ErrToken = errors.New("invalid token")
func HashPassword(plain string) (string, error) {
b, err := bcrypt.GenerateFromPassword([]byte(plain), 12)
return string(b), err
}
func CheckPassword(hash, plain string) bool {
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(plain)) == nil
}
type Claims struct {
UID int64 `json:"uid"`
Role string `json:"role"`
jwt.RegisteredClaims
}
func Sign(secret []byte, uid int64, role string) (string, error) {
return SignWithTTL(secret, uid, role, 72*time.Hour)
}
func SignWithTTL(secret []byte, uid int64, role string, ttl time.Duration) (string, error) {
t := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims{
UID: uid, Role: role,
RegisteredClaims: jwt.RegisteredClaims{ExpiresAt: jwt.NewNumericDate(time.Now().Add(ttl))},
})
return t.SignedString(secret)
}
func Parse(secret []byte, token string) (*Claims, error) {
c := &Claims{}
parsed, err := jwt.ParseWithClaims(token, c, func(t *jwt.Token) (any, error) {
m, ok := t.Method.(*jwt.SigningMethodHMAC)
if !ok || subtle.ConstantTimeCompare([]byte(m.Alg()), []byte("HS256")) != 1 {
return nil, ErrToken
}
return secret, nil
}, jwt.WithValidMethods([]string{"HS256"}))
if err != nil || !parsed.Valid {
return nil, ErrToken
}
return c, nil
}