API에서 404 오류가 발생합니다

Discourse 커뮤니티 여러분,

현재 Discourse API 엔드포인트, 특히 사용자 정지(suspend) 관련 문제로 어려움을 겪고 있어 도움을 요청드립니다. 조언이나 해결책을 주시면 감사하겠습니다.

문제 요약

  1. 404 Not Found:

    • 다음 엔드포인트를 사용할 때:
      /admin/users/15/suspend.json, 사용자가 존재함에도 불구하고 일관되게 “페이지를 찾을 수 없음” 오류가 발생합니다.
    • 대안 엔드포인트인
      /admin/u/15/suspend.json도 시도해 보았으나 동일한 문제가 발생합니다.
  2. 예상치 못한 HTML 응답:

    • 기대했던 JSON 응답 대신 "Oops! That page doesn’t exist or is private."라는 메시지가 포함된 HTML 페이지가 반환됩니다.
    • 요청에 curl을 사용하든 PowerShell을 사용하든 관계없이 이 문제가 발생합니다.
  3. API 키 및 권한:

    • 사용하는 API 키는 전체 관리자 권한이 있음에도 불구하고 요청은 계속 404 오류를 반환합니다.
    • 정지 작업으로 제한된 세분화된 키(granular keys)와 읽기 전용 키도 테스트해 보았으나 문제가 지속됩니다.
    • 흥미롭게도 브라우저로 해당 엔드포인트에 액세스하면 완벽하게 작동하지만, API 키를 사용하여 API 요청을 보낼 때는 실패합니다.

요청 예시

curl 예시

curl -X PUT "https://your-discourse-domain.com/admin/users/15/suspend.json" \
-H "Api-Key: [REDACTED_API_KEY]" \
-H "Api-Username: system" \
-H "Content-Type: application/json" \
-d '{"suspend_until": "2024-12-31", "reason": "Violation of community guidelines"}'

PowerShell 예시

# Discourse에서 사용자를 정지하는 PowerShell 스크립트

$baseUrl = "https://your-discourse-domain.com"
$userId = 15
$apiKey = "[REDACTED_API_KEY]"
$apiUsername = "system"
$suspendUntil = "2024-12-31"
$reason = "Violation of community guidelines"

$headers = @{
    "Api-Key" = $apiKey
    "Api-Username" = $apiUsername
    "Content-Type" = "application/json"
}

$body = @{
    suspend_until = $suspendUntil
    reason = $reason
} | ConvertTo-Json

$endpoint = "$baseUrl/admin/users/$userId/suspend.json"

try {
    $response = Invoke-RestMethod -Uri $endpoint -Method Put -Headers $headers -Body $body -ErrorAction Stop
    Write-Host "User suspended successfully!" -ForegroundColor Green
} catch {
    Write-Host "Error suspending user:" -ForegroundColor Red
    Write-Host $_.Exception.Message
}

추가 정보

  • Discourse 버전: 3.4.0.beta3
  • 실시한 문제 해결 단계:
    User-Agent 및 Referer를 포함하여 요청 헤더를 조정해 보았으나 효과가 없었습니다.

이 문제들을 해결하는 데 도움이 될 통찰력이나 제안이 있다면 매우 감사하겠습니다. 시간 내어 도와주셔서 미리 감사합니다!

감사합니다,
Ross

제시하신 예제는 예상되는 매개변수를 기준으로 테스트 사이트에서 그대로 작동합니다:

○ → curl -i -X PUT "https://try.discourse.org/admin/users/41/suspend.json" \
  -H "Api-Key: swordfish" \
  -H "Api-Username: michael" \
  -H "Content-Type: application/json" \
  -d '{"suspend_until": "2024-12-31", "reason": "Violation of community guidelines"}'

HTTP/2 200 
server: nginx
date: Mon, 11 Nov 2024 19:27:44 GMT
content-type: application/json; charset=utf-8
vary: Accept-Encoding
x-frame-options: SAMEORIGIN
x-xss-protection: 0
x-content-type-options: nosniff
x-permitted-cross-domain-policies: none
referrer-policy: strict-origin-when-cross-origin
x-discourse-username: michael
x-discourse-route: users/suspend
cache-control: no-cache, no-store
x-request-id: fe9c5ddc-b11a-45ba-ab41-9403eb53f255
cdck-proxy-id: app-router-tiehunter03.sea1
strict-transport-security: max-age=31536000
cdck-proxy-id: app-balancer-tieinterceptor1b.sea1

{
  "suspension": {
    "suspend_reason": "Violation of community guidelines",
    "full_suspend_reason": "Violation of community guidelines",
    "suspended_till": "2024-12-31T00:00:00.000Z",
    "suspended_at": "2024-11-11T19:27:44.927Z",
    "suspended_by": {
      "id": 85,
      "username": "michael",
      "name": "Michael Brown",
      "avatar_template": "/user_avatar/try.discourse.org/michael/{size}/639_2.png"
    }
  }
}
  • API 키 검증
    해당 키로 간단한 GET 요청을 보냈을 때 Discourse가 유효한 사용자 인증(x-discourse-username)을 표시합니까?
  • 사용자 ID 검증
    해당 ID가 실제로 존재합니까? 존재하지 않으면 404 오류가 발생합니다.
  • Cloudflare 뒤에서 요청하고 계신가요?
    Cloudflare가 매개변수를 교란시킬 수 있습니다.
  1. API 키 검증
    다음 명령어를 사용하여 API 키가 유효한 것으로 확인되었습니다:

    curl -X GET "https://redactedurl.com/admin/users/list/active.json" -H "Api-Key: LIVEPRODKEYHERE" -H "Api-Username: system"
    

    응답(기밀성을 위해 민감한 데이터는 마스킹 처리됨)은 다음과 같습니다:

    [
      {
        "id": 1,
        "username": "User1",
        "name": "Redacted",
        "avatar_template": "/user_avatar/yourforum.com/user1/{size}/avatar.png",
        "active": true,
        "admin": true,
        "moderator": true,
        "trust_level": 4,
        "title": "Recognized Member",
        "days_visited": 6,
        "post_count": 3
      },
      {
        "id": 19,
        "username": "User2",
        "name": "Redacted",
        "avatar_template": "/letter_avatar_proxy/v4/letter/j/{size}.png",
        "active": true,
        "admin": false,
        "moderator": false,
        "trust_level": 1,
        "title": "Member (Unverified)"
      },
      {
        "id": 3,
        "username": "User3",
        "name": "Redacted",
        "avatar_template": "/user_avatar/yourforum.com/user3/{size}/avatar.png",
        "active": true,
        "admin": true,
        "moderator": true,
        "trust_level": 4,
        "title": "Community Founder"
      },
      {
        "id": -1,
        "username": "system",
        "name": "system",
        "avatar_template": "/user_avatar/yourforum.com/system/{size}/avatar.png",
        "active": true,
        "admin": true,
        "moderator": true,
        "trust_level": 4,
        "title": "Bot"
      }
    ]
    
  2. 사용자 존재 확인
    테스트 사용자(ID: 15)는 /admin/users/15/suspend.json을 사용하여 사용자 데이터를 조회함으로써 존재함이 확인되었습니다:

    {
      "id": 15,
      "username": "User15",
      "active": true,
      "admin": false,
      "moderator": false,
      "trust_level": 0,
      "days_visited": 1,
      "post_count": 0,
      "can_send_activation_email": true,
      "can_activate": false,
      "can_deactivate": true,
      "can_grant_admin": true,
      "can_grant_moderation": true,
      "can_impersonate": true,
      "groups": [
        {
          "name": "trust_level_0",
          "bio_excerpt": "New members with limited abilities"
        }
      ]
    }
    

  1. 네트워크 구성
    해당 사이트는 Cloudflare를 사용하지 않습니다. 대신 NGINX 리버스 프록시 뒤에 운영되고 있습니다. 애플리케이션은 내부적으로 포트 8080에서 리스닝하며, 외부 접근을 위한 SSL 종료는 포트 443에서 NGINX가 처리합니다. app.yml 설정은 SSL 및 인증서 관리를 NGINX가 처리하여 안전한 연결과 가용성을 보장하기 때문에 포트 443에 직접 바인딩하지 않습니다.

안녕하세요,
이 사안에 대해 후속 조사를 해본 결과, API 키의 글로벌 스코프에 suspend 스코프가 누락된 것 같습니다. 저도 동일한 오류를 겪고 있었습니다. 작동하려면 suspend 스코프가 포함된 granular 키로 키를 교체해야 했습니다. 또한 unsuspend 기능도 작동하기를 희망했지만, 아직 API를 통해 사용할 수 없는 것 같습니다.