feat: implement auth handler, middleware, and router

domain/context.go: extend WithUser/UserFromContext with session ID

handler/response.go: respondJSON/respondError with domain→HTTP status
  mapping (404/403/401/409/400/415/500)
handler/middleware.go: Bearer JWT extraction, ParseAccessToken,
  domain.WithUser injection; aborts with 401 JSON on failure
handler/auth_handler.go: Login, Refresh, Logout, ListSessions,
  TerminateSession
handler/router.go: /health, /api/v1/auth routes; login and refresh
  are public, session routes protected by AuthMiddleware

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 00:43:41 +03:00
parent 296f44b4ed
commit caeff6786e
5 changed files with 299 additions and 7 deletions
+15 -7
View File
@@ -7,18 +7,26 @@ type ctxKey int
const userKey ctxKey = iota
type contextUser struct {
ID int16
IsAdmin bool
ID int16
IsAdmin bool
SessionID int
}
func WithUser(ctx context.Context, userID int16, isAdmin bool) context.Context {
return context.WithValue(ctx, userKey, contextUser{ID: userID, IsAdmin: isAdmin})
// WithUser stores user identity and current session ID in ctx.
func WithUser(ctx context.Context, userID int16, isAdmin bool, sessionID int) context.Context {
return context.WithValue(ctx, userKey, contextUser{
ID: userID,
IsAdmin: isAdmin,
SessionID: sessionID,
})
}
func UserFromContext(ctx context.Context) (userID int16, isAdmin bool) {
// UserFromContext retrieves user identity from ctx.
// Returns zero values if no user is stored.
func UserFromContext(ctx context.Context) (userID int16, isAdmin bool, sessionID int) {
u, ok := ctx.Value(userKey).(contextUser)
if !ok {
return 0, false
return 0, false, 0
}
return u.ID, u.IsAdmin
return u.ID, u.IsAdmin, u.SessionID
}