added comments

This commit is contained in:
u80864958
2025-05-02 10:39:35 +02:00
parent fb7d5a623a
commit 14b57b57e8
16 changed files with 73 additions and 29 deletions

View File

@@ -6,7 +6,6 @@ import (
"fmt"
"log"
"net/http"
"slices"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
@@ -14,6 +13,7 @@ import (
"git.schreifuchs.ch/schreifuchs/ng-blog/backend/internal/model"
)
// Signup handles user signup by decoding request body, hashing the password, and saving user data to the database.
func (s *Service) Signup(w http.ResponseWriter, r *http.Request) {
var err error
var login Login
@@ -50,6 +50,7 @@ func (s *Service) Signup(w http.ResponseWriter, r *http.Request) {
}
}
// Login handles user login by decoding request body, verifying credentials, and returning a JWT token.
func (s *Service) Login(w http.ResponseWriter, r *http.Request) {
var login Login
var user model.User
@@ -86,6 +87,7 @@ func (s *Service) Login(w http.ResponseWriter, r *http.Request) {
w.Write(res)
}
// Logout handles user logout by invalidating the JWT and saving it to the database.
func (s *Service) Logout(w http.ResponseWriter, r *http.Request) {
token, err := extractToken(r)
if err != nil {
@@ -109,28 +111,3 @@ func (s *Service) Logout(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
func (s *Service) Authenticated(next http.HandlerFunc, roles ...model.Role) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Our middleware logic goes here...
token, err := extractToken(r)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
claims, err := s.validateJWT(token)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
// if roles specified check if satisfied
if len(roles) > 0 && !slices.Contains(roles, claims.Role) {
w.WriteHeader(http.StatusForbidden)
return
}
r = writeToContext(r, &claims)
next(w, r)
})
}

View File

@@ -3,7 +3,6 @@ package auth
import (
"errors"
"fmt"
"log"
"net/http"
"strings"
"time"
@@ -28,6 +27,7 @@ func (s *Service) createJWT(user *model.User) (token string, err error) {
return jwt.NewWithClaims(jwt.SigningMethodHS512, claims).SignedString([]byte(s.cfg.Secret))
}
// validateJWT returns the token Claims and if token ist invalid ErrJWTInvalid
func (s *Service) validateJWT(tokenString string) (claims Claims, err error) {
_, err = jwt.ParseWithClaims(tokenString, &claims, func(token *jwt.Token) (any, error) {
// Don't forget to validate the alg is what you expect:
@@ -40,12 +40,13 @@ func (s *Service) validateJWT(tokenString string) (claims Claims, err error) {
if err != nil {
return
}
log.Println(claims)
if claims.ExpiresAt.Before(time.Now()) {
err = ErrJWTInvalid
return
}
// check if user has logged out this token
var invalidated bool
err = s.db.Model(&model.InvalidJWT{}).
Select("count(*) > 0").
@@ -60,6 +61,7 @@ func (s *Service) validateJWT(tokenString string) (claims Claims, err error) {
return
}
// extractToken extracts the Bearer token from the request
func extractToken(r *http.Request) (token string, err error) {
tokenHeader := r.Header.Get("Authorization") // Grab the token from the header

View File

@@ -0,0 +1,34 @@
package auth
import (
"net/http"
"slices"
"git.schreifuchs.ch/schreifuchs/ng-blog/backend/internal/model"
)
// Authenticated: This function is a middleware that authenticates incoming HTTP requests using JWT tokens and role-based access control.
func (s *Service) Authenticated(next http.HandlerFunc, roles ...model.Role) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Our middleware logic goes here...
token, err := extractToken(r)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
claims, err := s.validateJWT(token)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
// if roles specified check if satisfied
if len(roles) > 0 && !slices.Contains(roles, claims.Role) {
w.WriteHeader(http.StatusForbidden)
return
}
r = writeToContext(r, &claims)
next(w, r)
})
}

View File

@@ -11,6 +11,7 @@ import (
"gorm.io/gorm/clause"
)
// Config defines a struct for configuration settings, often loaded from environment variables.
type Config struct {
Secret string `env:"SECRET"`
ValidDuration time.Duration `env:"VALID_DURATION"`
@@ -19,11 +20,13 @@ type Config struct {
DefaultRole model.Role `env:"DEFAULT_ROLE"`
}
// Service Represents a service with configuration and database connection.
type Service struct {
cfg *Config
db *gorm.DB
}
// New creates a new Service instance, initializing a default admin user and saving it to the database.
func New(cfg *Config, db *gorm.DB) *Service {
user := model.NewUser()
var err error
@@ -42,16 +45,20 @@ func New(cfg *Config, db *gorm.DB) *Service {
}
}
// Claims struct represents JWT claims, including role and user ID, extending the standard jwt.RegisteredClaims.
type Claims struct {
Role model.Role `json:"rl"`
UserID uint `json:"uid"`
jwt.RegisteredClaims
}
// Login struct represents user login credentials with a name and password.
type Login struct {
Name string `json:"name"`
Password string `json:"Password"`
}
// LoginResponse Represents the response from a login endpoint, containing a JWT token.
type LoginResponse struct {
Token string `json:"token"`
}