Add RBAC support with roles, permissions, and session management. Implement middleware for authentication and CSRF protection. Enhance audit logging with additional fields. Update HTTP handlers and routes for new features.
This commit is contained in:
102
internal/auth/user.go
Normal file
102
internal/auth/user.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID string
|
||||
Username string
|
||||
PasswordHash string
|
||||
Role string // Legacy field, kept for backward compatibility
|
||||
CreatedAt string
|
||||
}
|
||||
|
||||
type UserStore struct {
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
func NewUserStore(db *sql.DB) *UserStore {
|
||||
return &UserStore{DB: db}
|
||||
}
|
||||
|
||||
// GetUserByUsername retrieves a user by username
|
||||
func (s *UserStore) GetUserByUsername(ctx context.Context, username string) (*User, error) {
|
||||
var user User
|
||||
err := s.DB.QueryRowContext(ctx,
|
||||
`SELECT id, username, password_hash, role, created_at FROM users WHERE username = ?`,
|
||||
username).Scan(&user.ID, &user.Username, &user.PasswordHash, &user.Role, &user.CreatedAt)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// GetUserByID retrieves a user by ID
|
||||
func (s *UserStore) GetUserByID(ctx context.Context, userID string) (*User, error) {
|
||||
var user User
|
||||
err := s.DB.QueryRowContext(ctx,
|
||||
`SELECT id, username, password_hash, role, created_at FROM users WHERE id = ?`,
|
||||
userID).Scan(&user.ID, &user.Username, &user.PasswordHash, &user.Role, &user.CreatedAt)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// CreateUser creates a new user
|
||||
func (s *UserStore) CreateUser(ctx context.Context, username, password string) (*User, error) {
|
||||
passwordHash, err := HashPassword(password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userID := username // Using username as ID for simplicity, could use UUID
|
||||
_, err = s.DB.ExecContext(ctx,
|
||||
`INSERT INTO users (id, username, password_hash) VALUES (?, ?, ?)`,
|
||||
userID, username, passwordHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.GetUserByID(ctx, userID)
|
||||
}
|
||||
|
||||
// UpdatePassword updates a user's password
|
||||
func (s *UserStore) UpdatePassword(ctx context.Context, userID, newPassword string) error {
|
||||
passwordHash, err := HashPassword(newPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.DB.ExecContext(ctx,
|
||||
`UPDATE users SET password_hash = ? WHERE id = ?`,
|
||||
passwordHash, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
// Authenticate verifies username and password
|
||||
func (s *UserStore) Authenticate(ctx context.Context, username, password string) (*User, error) {
|
||||
user, err := s.GetUserByUsername(ctx, username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
valid, err := VerifyPassword(password, user.PasswordHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !valid {
|
||||
return nil, errors.New("invalid password")
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
Reference in New Issue
Block a user