auth.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package auth
  2. import (
  3. "errors"
  4. "time"
  5. "github.com/golang-jwt/jwt/v5"
  6. "gogs.dmsc.dev/arp/models"
  7. "golang.org/x/crypto/bcrypt"
  8. )
  9. // Token expiration: 10 years
  10. const TokenExpiration = 10 * 365 * 24 * time.Hour
  11. // JWT secret key - in production this should be loaded from environment
  12. var jwtSecret = []byte("your-secret-key-change-in-production")
  13. // Claims represents the JWT claims
  14. type Claims struct {
  15. UserID uint `json:"user_id"`
  16. Email string `json:"email"`
  17. Roles []RoleClaim `json:"roles"`
  18. Permissions []string `json:"permissions"`
  19. jwt.RegisteredClaims
  20. }
  21. // RoleClaim represents a role in the JWT
  22. type RoleClaim struct {
  23. ID uint `json:"id"`
  24. Name string `json:"name"`
  25. }
  26. // HashPassword hashes a password using bcrypt
  27. func HashPassword(password string) (string, error) {
  28. bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
  29. return string(bytes), err
  30. }
  31. // CheckPassword verifies a password against a hash
  32. func CheckPassword(password, hash string) bool {
  33. err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
  34. return err == nil
  35. }
  36. // GenerateToken creates a JWT token for a user
  37. func GenerateToken(user models.User) (string, error) {
  38. // Build role claims
  39. roles := make([]RoleClaim, len(user.Roles))
  40. for i, role := range user.Roles {
  41. roles[i] = RoleClaim{
  42. ID: role.ID,
  43. Name: role.Name,
  44. }
  45. }
  46. // Build permission codes (deduplicated)
  47. permSet := make(map[string]bool)
  48. for _, role := range user.Roles {
  49. for _, perm := range role.Permissions {
  50. permSet[perm.Code] = true
  51. }
  52. }
  53. permissions := make([]string, 0, len(permSet))
  54. for perm := range permSet {
  55. permissions = append(permissions, perm)
  56. }
  57. claims := Claims{
  58. UserID: user.ID,
  59. Email: user.Email,
  60. Roles: roles,
  61. Permissions: permissions,
  62. RegisteredClaims: jwt.RegisteredClaims{
  63. ExpiresAt: jwt.NewNumericDate(time.Now().Add(TokenExpiration)),
  64. IssuedAt: jwt.NewNumericDate(time.Now()),
  65. },
  66. }
  67. token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  68. return token.SignedString(jwtSecret)
  69. }
  70. // ValidateToken validates a JWT token and returns the claims
  71. func ValidateToken(tokenString string) (*Claims, error) {
  72. token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
  73. if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
  74. return nil, errors.New("unexpected signing method")
  75. }
  76. return jwtSecret, nil
  77. })
  78. if err != nil {
  79. return nil, err
  80. }
  81. if claims, ok := token.Claims.(*Claims); ok && token.Valid {
  82. return claims, nil
  83. }
  84. return nil, errors.New("invalid token")
  85. }
  86. // SetJWTSecret sets the JWT secret key (for testing or configuration)
  87. func SetJWTSecret(secret []byte) {
  88. jwtSecret = secret
  89. }