Files
golib/hwsauth/model.go

87 lines
2.5 KiB
Go

package hwsauth
import (
"context"
)
type authenticatedModel[T Model] struct {
model T
fresh int64
}
func getNil[T Model]() T {
var result T
return result
}
// Model represents an authenticated user model.
// User types must implement this interface to be used with the authenticator.
type Model interface {
GetID() int // Returns the unique identifier for the user
}
// ContextLoader is a function type that loads a model from a context.
// Deprecated: Use CurrentModel method instead.
type ContextLoader[T Model] func(ctx context.Context) T
// LoadFunc is a function type that loads a user model from the database.
// It receives a context for cancellation, a transaction for database operations,
// and the user ID to load.
//
// Example:
//
// loadUser := func(ctx context.Context, tx *sql.Tx, id int) (User, error) {
// var user User
// err := tx.QueryRowContext(ctx,
// "SELECT id, username, email FROM users WHERE id = $1", id).
// Scan(&user.ID, &user.Username, &user.Email)
// return user, err
// }
type LoadFunc[T Model, TX DBTransaction] func(ctx context.Context, tx TX, id int) (T, error)
// Return a new context with the user added in
func setAuthenticatedModel[T Model](ctx context.Context, m authenticatedModel[T]) context.Context {
return context.WithValue(ctx, "hwsauth context key authenticated-model", m)
}
// Retrieve a user from the given context. Returns nil if not set
func getAuthorizedModel[T Model](ctx context.Context) (model authenticatedModel[T], ok bool) {
defer func() {
if r := recover(); r != nil {
// panic happened, return ok = false
ok = false
model = authenticatedModel[T]{}
}
}()
model, cok := ctx.Value("hwsauth context key authenticated-model").(authenticatedModel[T])
if !cok {
return authenticatedModel[T]{}, false
}
return model, true
}
// CurrentModel retrieves the authenticated user from the request context.
// Returns a zero-value T if no user is authenticated or context is nil.
//
// Example:
//
// func handler(w http.ResponseWriter, r *http.Request) {
// user := auth.CurrentModel(r.Context())
// if user.ID() == 0 {
// http.Error(w, "Not authenticated", http.StatusUnauthorized)
// return
// }
// fmt.Fprintf(w, "Hello, %s!", user.Username)
// }
func (auth *Authenticator[T, TX]) CurrentModel(ctx context.Context) T {
if ctx == nil {
return getNil[T]()
}
model, ok := getAuthorizedModel[T](ctx)
if !ok {
result := getNil[T]()
return result
}
return model.model
}