query-database/api/internal/auth/auth.go
2026-03-25 15:46:20 +08:00

88 lines
2.0 KiB
Go

package auth
import (
"crypto/subtle"
"database/sql"
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)
type Auth struct {
secret []byte
}
func New(secret string) *Auth {
return &Auth{secret: []byte(secret)}
}
func (a *Auth) Issue(userID string) (string, error) {
t := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": userID,
"iat": time.Now().Unix(),
"exp": time.Now().Add(7 * 24 * time.Hour).Unix(),
})
return t.SignedString(a.secret)
}
func (a *Auth) parseToken(token string) (string, error) {
parsed, err := jwt.Parse(token, func(t *jwt.Token) (any, error) {
if t.Method.Alg() != jwt.SigningMethodHS256.Alg() {
return nil, jwt.ErrSignatureInvalid
}
return a.secret, nil
})
if err != nil {
return "", err
}
if !parsed.Valid {
return "", jwt.ErrTokenInvalidClaims
}
claims, ok := parsed.Claims.(jwt.MapClaims)
if !ok {
return "", jwt.ErrTokenInvalidClaims
}
sub, ok := claims["sub"].(string)
if !ok || sub == "" {
return "", jwt.ErrTokenInvalidClaims
}
return sub, nil
}
func (a *Auth) RequireAuth(sqlite *sql.DB) gin.HandlerFunc {
return func(c *gin.Context) {
hdr := c.GetHeader("Authorization")
if hdr == "" || !strings.HasPrefix(hdr, "Bearer ") {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "未登录"})
return
}
token := strings.TrimSpace(strings.TrimPrefix(hdr, "Bearer "))
userID, err := a.parseToken(token)
if err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Token 无效"})
return
}
var exists int
if err := sqlite.QueryRow(`SELECT COUNT(1) FROM users WHERE id = ?`, userID).Scan(&exists); err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"message": "服务异常"})
return
}
if subtle.ConstantTimeEq(int32(exists), 1) != 1 {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "账号不存在"})
return
}
c.Set("userID", userID)
c.Next()
}
}
func UserID(c *gin.Context) string {
v, _ := c.Get("userID")
s, _ := v.(string)
return s
}