feat(authz): redirect deleted accounts to /login

detect soft-deleted users during authorization lookup
return a dedicated deleted-user result from auth services
redirect deleted accounts to /login in the handler
update repository, service, and handler tests for the new flow
This commit is contained in:
2026-05-08 09:04:28 +08:00
parent db5eba572f
commit e6bbaeffa6
8 changed files with 193 additions and 47 deletions
+19 -14
View File
@@ -126,24 +126,29 @@ func AuthorizeHandler(w http.ResponseWriter, r *http.Request) {
return
}
// Return result
writeAuthorizationResponse(w, r, result)
}
func writeAuthorizationResponse(w http.ResponseWriter, r *http.Request, result *models.AuthorizationResult) {
if result.RedirectRoute != "" {
log.Printf("✗ [Handler] Authorization redirect to %s (reason: %s)", result.RedirectRoute, result.Message)
http.Redirect(w, r, result.RedirectRoute, http.StatusFound)
return
}
response := map[string]interface{}{
"allowed": result.Allowed,
"reason": result.Message,
}
if result.Allowed {
log.Printf("✓ [Handler] Authorization ALLOWED - Returning 200 OK to client")
// Return sabat matching Authorizationsabat model for client compatibility
response := map[string]interface{}{
"allowed": result.Allowed,
"reason": result.Message,
}
sabat.RespondWithJSON(w, http.StatusOK, response)
} else {
log.Printf("✗ [Handler] Authorization DENIED - Returning 403 Forbidden to client (reason: %s)", result.Message)
// Return sabat matching Authorizationsabat model for client compatibility
response := map[string]interface{}{
"allowed": result.Allowed,
"reason": result.Message,
}
sabat.RespondWithJSON(w, http.StatusForbidden, response)
return
}
log.Printf("✗ [Handler] Authorization DENIED - Returning 403 Forbidden to client (reason: %s)", result.Message)
sabat.RespondWithJSON(w, http.StatusForbidden, response)
}
func collectClaimRoles(claims *models.Claims) []int {
+18
View File
@@ -10,6 +10,24 @@ import (
"testing"
)
func TestWriteAuthorizationResponseRedirectsToLogin(t *testing.T) {
req := httptest.NewRequest("POST", AuthCheckEndpoint, nil)
w := httptest.NewRecorder()
writeAuthorizationResponse(w, req, &models.AuthorizationResult{
Allowed: false,
RedirectRoute: "/login",
Message: "Account deleted",
})
if w.Code != http.StatusFound {
t.Fatalf("Expected status %d, got %d", http.StatusFound, w.Code)
}
if location := w.Header().Get("Location"); location != "/login" {
t.Fatalf("Expected redirect location /login, got %q", location)
}
}
func TestInitAuthService(t *testing.T) {
// Test that InitAuthService can be called
// It may panic if DB is not available, which is expected behavior