95 lines
2.6 KiB
Go
95 lines
2.6 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)
|
|
|
|
type contextKey string
|
|
|
|
func (c contextKey) String() string {
|
|
return "hwsauth context key" + string(c)
|
|
}
|
|
|
|
var authenticatedModelContextKey = contextKey("authenticated-model")
|
|
|
|
// 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, authenticatedModelContextKey, 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(authenticatedModelContextKey).(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
|
|
}
|