워드프레스 REST API 인증과 제한 및 제어

연재고품격 고품질 워드프레스 무료 사진 저장소완결2

REST API 개요에서 언제나 등장하는 것 중 하나는 인증(Authentication)입니다. 시스템 외부의 데이터 요청 및 교환 요구를 제어하지 않고 제공하는 것은 내부 보안 수준을 낮추는 것과 같습니다. 결국, 인증은 보안을 위한 것이며, 보안과 같습니다. 한 번 정도 간략하게 확인하는 정도로 이어갑니다.

워드프레스 REST API 인증 및 제한

워드프레스 REST API 인증

대부분 API 서비스가 비슷하지만, 워드프레스도 REST API 인증에 관하여 몇 가지를 코덱스에서 안내하고 있습니다. 몇 가지를 워드프레스, 그리고 보통의 ‘사용’ 개념 기준의 범주로 본다면 다음 2가지로 생각할 수 있습니다.

  • 쿠키와 Nonce
  • 플러그인

쿠키, Nonce

워드프레스 REST API 인증 이전에 워드프레스 표준 인증 방식이 쿠키 인증입니다. 워드프레스 REST API 인증은 쿠키와 함께 Nonce를 사용합니다. Nonce는 사용 기한이 있는 일종의 보안 토큰으로 CSRF(Cross-Site Request Forgery, 사이트 간 요청 변조) 대응 방안의 하나입니다.

쿠키는 워드프레스에 로그인하면 생성되며, Nonce 토큰은 워드프레스 내장 자바스크립트 API(wp-api)를 사용할 때는 자동으로 생성 및 전달됩니다. 결국, 쿠키와 Nonce 토큰 인증은 워드프레스 내부에서 API를 사용할 때의 기준입니다.

다음 1번과 2번 줄은 테마 inc/enqueue-script.php 파일 11번 줄을 빗금으로 비활성하고, 12번 줄 빗금을 제거한 것입니다.

// wp_enqueue_script( 'pics-js', get_theme_file_uri( '/assets/js/pics.js' ), array(), $pics_js_ver );
wp_enqueue_script( 'pics-js', get_theme_file_uri( '/assets/js/pics.js' ), array( 'wp-api' ), $pics_js_ver ); // 또는 wp_enqueue_script( 'wp-api' );
wp_enqueue_script( 'wp-util' );

2번 줄은 wp-api 플러그인을 활성화(대기열 등록)하는 것이며, 활성으로 사이트 소스에는 Backbone.js 및 Underscore.js 라이브러리와 wp-api 스크립트 파일이 추가되며, 다음처럼 REST URL, Nonce 토큰, 네임스페이스의 로컬 자바스크립트 데이터가 생성됩니다. 직접 확인해보세요.

// wp-api 활성화 후
var wpApiSettings = {"root":"http:\/\/localhost\/wp-json\/","nonce":"45ca087574","versionString":"wp\/v2\/"};

2번 줄 wp-api 활성화만으로 Underscore.js 라이브러리가 추가되지만, 위의 3번 줄 wp-util 스크립트를 등록하지 않으면, 예제에서 사용한 wp.template 함수를 사용할 수 없습니다.

다음은 지정한 제목으로 타입 post 포스트를 등록하는 예로, 내장 자바스크립트를 사용한 자동 인증으로 포스트를 등록합니다.

var post = new wp.api.models.Post({
    title: '이것은 내장 자바스크립트를 사용한 포스트입니다',
    content: '내장 자바스크립트를 사용하면 자동 인증합니다.',
    status: 'publish'
});
post.save();

내부 사용일 때도 워드프레스 내장 자바스크립트를 사용하지 않는다면, Ajax 요청 시 수동으로 Nonce 토큰을 생성하고 전달해야 합니다. REST API를 사용한다면 ‘X-WP-Nonce’ header로 전달할 수 있으며, Nonce 생성할 때 wp_rest 액션 이름 사용에 주의하세요.

wp_localize_script( 'pics-js', 'customAuth', array(
    'custom_url' => esc_url_raw( rest_url() ),
    'custom_nonce' => wp_create_nonce( 'wp_rest' )
) );

다음 코드는 jQuery Ajax POST 요청으로 타입 post에 포스트를 등록하는 것입니다. 코드처럼 직접 X-WP-Nonce header로 Nonce 토큰을 전달해 인증해야 합니다.

jQuery.ajax( {
    url: customAuth.custom_url + 'wp/v2/posts',
    method: 'POST',
    beforeSend: function ( xhr ) {
        xhr.setRequestHeader( 'X-WP-Nonce', customAuth.custom_nonce );
    },
    data:{
        title: '수동 요청에 의한 포스트 등록',
        content: '수동 Ajax 요청은 요청마다 Nonce 전달로 인증해야 합니다.',
        status: 'publish'
    }
} );

쿠키와 Nonce 인증은 워드프레스 내부에 로그인하여 REST API를 사용한 때, 그리고 로그인 사용자가 해당 요청에 연결된 역할(Role) 또는 권한(Capability)이 있어야 합니다.

플러그인

먼저, ‘플러그인’은 설치 방식의 저장소 플러그인만을 말하는 것이 아닙니다. 직접 작성한 코드에 워드프레스 플러그인 헤더 텍스트를 추가하여 활성화한 것, 함수 wp_enqueue_script로 추가한 워드프레스 내장 API 등 개념 기준으로 범주를 확장해야 합니다.

플러그인을 사용하는 목적은 워드프레스 외부의 웹 및 애플리케이션에서 워드프레스 시스템 내부로의 인증을 위한 것입니다. 코덱스에서 안내하는 플러그인은 다음과 같은데, 인증 방법에 따라 구분하여 인증 개요에 관한 안내를 위한 것이며, 플러그인 자체가 절대적인 것은 아닙니다.

‘HTTP 기본 인증’의 Basic-Auth 플러그인은 워드프레스 시스템의 사용자 아이디와 암호를 사용하므로 보안 수준이 낮아 웹처럼 공개 환경에서 사용하기 어려우므로 특정 환경이나 상황에 제한적으로 사용해야 합니다. ‘이중 인증(Two-Factor Authentication)’ 방식의 Application Passwords 플러그인은 워드프레스 시스템의 사용자 아이디와 함께 새로 추가한 인증 암호를 사용하므로 기본 인증보다는 한 단계 높은 수준이지만, 추가한 암호도 노출되는 것으로 쉽게 디코드할 수 있습니다. 워드프레스 시스템, 쉽게 일반적인 워드프레스 로그인 화면에서 로그인할 수 없다는 것을 제외하면 HTTP 기본 인증과 마찬가지입니다.

상대적이며 개인 사고의 영역이므로 규모에 관하여 객관적으로 단정할 수는 없지만, 규모를 떠나서 외부에 워드프레스 REST API 서비스를 제공한다면 ‘JWT(JSON Web Tokens)’ 또는 ‘OAuth’ 인증 방식을 사용하는 것이 좋습니다. 이런 인증 방식은 직접 학습하기 바라며, 모든 인증 방식과 더불어 최소한 ‘HTTPS’ 암호화 연결은 선행 요소에 두는 게 좋습니다.

워드프레스 REST API 제한과 제어

워드프레스 REST API 인증에 관한 정보는 대부분 GET 요청(Method)을 제외한 POST 요청 등에 집중되어 있습니다. 워드프레스 REST API 기본은, 일부를 제외하면 GET 요청에 인증 제한을 두지 않습니다.

예제 사이트에서 로그아웃 또는 POSTMAN 및 다른 세션의 브라우저에서 다음 엔드포인트로 접근하면 즉시 응답 결과를 확인할 수 있는데, 지난 과정에서 모두 확인한 것입니다.

  • localhost/wp-json/wp/v2/posts?per_page=100
  • localhost/wp-json/wp/v2/media?per_page=100
  • localhost/wp-json/wp/v2/comments?per_page=100

또, 워드프레스 REST API 관련 특정 제어를 한때가 없는 자신의 워드프레스 사이트나 알고 있는 유명 워드프레스 사이트의 도메인을 위의 localhost와 대체하여 확인하면 대부분 공개 상태일 것입니다.

워드프레스 REST API 요청 제한 설정은 기준에 따라 다를 수 있는데, 예제는 GET 요청만 사용하며, ‘사이트 내 REST API 사용 페이지’에서만 허용하는 것을 기준으로 정합니다. GET 요청만 사용한다는 것은 POST 요청 등은 로그인 상태에서 역시 사이트 내에서만 허용하므로 다른 설정이 요구되지 않는다는 뜻입니다.

워드프레스 REST API 전체 요청을 로그인 상태로 제한

우선, 테마 루트의 inc/rest-api.php 파일 맨 아래에 코덱스에서 제공하는 다음 코드를 추가하고 저장합니다.

add_filter( 'rest_authentication_errors', function( $result ) {
    if ( ! empty( $result ) ) {
        return $result;
    }
    if ( ! is_user_logged_in() ) { // All REST API Disable
        return new WP_Error( 'rest_restrict', '사이트 내에서만 제공합니다.', array( 'status' => 401 ) );
    }
    return $result;
});

로그아웃 상태에서 ‘더보기’ 기능이 있는 모든 아카이브 페이지의 ‘더보기’ 버튼과 싱글 이미지 포스트 페이지의 코멘트 및 ‘댓글보기’를 클릭하면 인증되지 않은 401 상태 코드가 나올 것입니다. 또, 모든 엔드포인트를 브라우저 또는 POSTMAN 애플리케이션에 직접 추가하고 확인해도 다음처럼 결과는 같습니다. 로그인 상태 조건의 위의 5번 줄 코드에 의한 결과입니다.

// 401 상태 코드 응답
{
    code: "rest_restrict",
    message: "사이트 내에서만 제공합니다.",
    data: {
        status: 401
    }
}

그러나, 로그인 상태에서 브라우저에 엔드포인트를 직접 입력하여 요청하는 것을 제한하지 못합니다. 또, 로그인 상태 조건은 편리한 제한 방법이지만, 비공개 사이트가 아닌 예제처럼 로그인 전 방문자에게 제공하는 데이터를 REST API로 구성한 때는 효율적인 방법이 아닙니다.

HTTP referer

로그인 상태 조건 대신 워드프레스 wp_get_referer 함수를 사용하면 다음과 같습니다. 직전에 추가한 코드에서 다음 조건으로 변경하고 저장하세요.

if ( wp_get_referer() === false ) {
    return new WP_Error( 'rest_restrict', '사이트 내에서만 제공합니다.', array( 'status' => 401 ) );
}

하나만 예를 들어, 사이트 내에서 둘러보기 페이지의 ‘더보기’ 버튼으로 요청은 가능하지만, 직접 엔드포인트를 브라우저에 추가하고 요청하면 제한합니다. 로그인 상태에서도 마찬가지입니다.

완벽한 방법은 아니지만, 가장 쉽게 사이트 페이지 외부의 GET 요청을 제한하는 최소한의 방법이므로 예제에서는 이 조건을 사용합니다.

HTTP header

CORS(Cross-Origin Resource Sharing), 다른 도메인에서 요청이 있을 때 리소스를 공유하는 정책을 뜻하는 것으로, 다음 함수는 워드프레스 REST API 요청 시 관련 HTTP header를 전송합니다.

// https://developer.wordpress.org/reference/functions/rest_send_cors_headers/#source
function rest_send_cors_headers( $value ) {
    $origin = get_http_origin();
 
    if ( $origin ) {
        // Requests from file:// and data: URLs send "Origin: null"
        if ( 'null' !== $origin ) {
            $origin = esc_url_raw( $origin );
        }
        header( 'Access-Control-Allow-Origin: ' . $origin );
        header( 'Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, PATCH, DELETE' );
        header( 'Access-Control-Allow-Credentials: true' );
        header( 'Vary: Origin' );
    }
 
    return $value;
}

위의 함수에 의한 header는 rest_pre_serve_request 필터 훅에 연결되는데, 요청에 관한 모든 header를 직접 추가하여 정의할 수 있습니다.

add_action( 'rest_api_init', 'add_custom_cors' );
function add_custom_cors() {
    remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
    add_filter( 'rest_pre_serve_request', function( $value ) {
        header( 'Access-Control-Allow-Origin: ' . esc_url_raw( site_url() ) );
        header( 'Access-Control-Allow-Methods: GET' );
        // 모든 원하는 header 계속 추가
        return $value;
    });
}

예제에서 사용하지 않으므로 워드프레스 REST API 외부 요청 제어에 관한 HTTP header 정의의 참고 정도로 생각하세요.

permission_callback

구글 지도 마커를 위한 예제의 커스텀 라우트 코드는 다음과 같습니다. 기여자 로그인 제외 라우트입니다.

register_rest_route( $namespace, '/geo/', array(
    'methods' => WP_REST_Server::READABLE,
    'callback' => 'picspress_get_geo',
) );

다음처럼 접근 콜백 함수를 추가하여 인증한 사용자가 사이트에 가진 역할 또는 권한을 조건으로 데이터 제공 여부를 정의할 수 있습니다.

register_rest_route( $namespace, '/geo/', array(
    'methods' => WP_REST_Server::READABLE,
    'callback' => 'picspress_get_geo',
    'permission_callback' => function () {
        return current_user_can( 'read' );
    }
) );

개별 라우트 및 엔드포인트 제어가 필요할 때 쉽게 적용할 수 있습니다.

포스트 타입과 분류 및 코멘트

워드프레스 기본 post, page 포스트 타입과 category, post_tag 분류 라우트 및 엔드포인트는 예제에서 사용하지 않는데, 기본으로 REST API에 등록되어 있습니다. 다음 코드로 등록 제외할 수 있습니다.

add_action( 'init', function() {
    global $wp_post_types, $wp_taxonomies;
    $wp_post_types['post']->show_in_rest = false;
    $wp_post_types['page']->show_in_rest = false;
    $wp_taxonomies['category']->show_in_rest = false;
    $wp_taxonomies['post_tag']->show_in_rest = false;
} );

그러나, 예제의 기준은 post, page 타입의 포스트에 대한 REST API 제외이지 해당 포스트의 코멘트는아닙니다. 커스텀 포스트 타입 pic_album도 마찬가지입니다. 따라서, 코멘트 REST API를 사용한다면 관련 포스트 타입도 REST API를 허용해야 합니다. 또, 포스트 타입에 대한 REST API 엔드포인트에 분류 파라미터를 포함한다면 관련된 분류의 REST API도 허용해야 합니다.

앞의 코드는 참고 정도의 내용으로 생각하고, 예제에서는 pic_album 타입만 REST API true로 변경하면 됩니다. 완성 파일에 변경하여 제공합니다.

암호화 연결, https

프로토콜 https, 직접적인 REST API 제한보다는 요청과 연결의 기본 보안을 위해 필요한 요소입니다. 물론, 프로토콜도 외부의 요청 제한에 기준이 되므로 허용하지 않은 요청 접근 제어를 위한 방법이 될 수 있습니다.

admin-ajax.php

앞에서 살핀 최소한 및 다양한 요청 제한과 제어는, 사이트 페이지 내에서만 워드프레스 REST API 응답을 허용하는, 예제 사이트 GET 요청 제한 기준에 맞추기 위한 목적으로 나열한 것입니다. 물론, 다른 요청에도 사용할 수 있으며 참고 수준의 내용도 있습니다.

제한과 제어는 워드프레스 REST API 기본이 GET 요청 ‘공개’로 정의되어 있기 때문인데, 자신의 콘텐츠를 누군가 원격에서 엔드포인트만으로 스크랩하여 편리한 구조의 JSON 데이터를 열람 또는 가공하여 활용하는 것을 좋아하는 운영자는 없을 것입니다.

REST API는 대부분 특정 지식이 있는 개발자 그룹 정도의 대상을 기준으로 설계하고 제공하는 때가 많고, 내부보다는 외부의 웹 및 애플리케이션 요청에 대응한 데이터 교환 서비스가 핵심 목적이므로 인증 과정 필수가 전제 조건이라면, 워드프레스 REST API 기본 GET 요청의 공개가 잘못된 것으로 생각할 수는 없습니다. 그래도 보통의 사용자는 이런 사항을 알기 어려우므로 옵션 항목 제공 정도는 필요할 것입니다.

사실, 예제의 Ajax 통신 콘텐츠 추가 호출(Ajax Load More)은 사이트 내부의 데이터를 내부에서 사용하기 위한 것이므로 워드프레스 REST API가 아닌 워드프레스의 Ajax API를 사용하는 것이 제어 및 보안, 속도 등에서 가장 알맞습니다. 구성 단계는 REST API 방식이 조금 더 간단합니다.

한편, 워드프레스 REST API는 PHP에서 API를 요청할 수 있는데, 다음은 이미지 포스트의 제목 100개를 출력하는 간단한 예입니다.

$request = new WP_REST_Request( 'GET', '/wp/v2/media' );
$request->set_param( 'per_page', 100 );
$response = rest_do_request( $request );
//$headers = $response->get_headers();
$body = $response->get_data();
if ( $body ) {
    foreach ( $body as $data ) {
        echo $data['title']['rendered'];
    }
}

이처럼 PHP 코드로 REST API에 접근하고, 워드프레스 Ajax API 기준으로 요청 데이터를 출력하는 방법도 가능합니다.

워드프레스 Ajax API 일부인 admin-ajax.php는 사이트 프런트 엔드와 벡 엔드의 요청을 처리할 수 있으며, 인증 및 비인증 상태(사용자)에 모두 대응할 수 있습니다. 워드프레스 방식의 폼 데이터 처리로 부를 수 있는 admin-post.php와 비슷합니다.

워드프레스 HTTP API

REST API는 HTTP 전송 모델에 의한 데이터 교환입니다. 따로 인지하지 않고 늘 사용하는 ‘웹’ 방식이라고 생각하면 됩니다. 워드프레스는 REST API 이전에 ‘워드프레스 HTTP API’를 제공하고 있습니다. 다만, PHP 내에서 사용할 수 있습니다.

// 워드프레스 HTTP API 함수
wp_remote_get()
wp_remote_post()
wp_remote_head()
wp_remote_request()

wp_remote_retrieve_body()
wp_remote_retrieve_header()
wp_remote_retrieve_headers()
wp_remote_retrieve_response_code()
wp_remote_retrieve_response_message()

워드프레스 HTTP API는 PHP 내 사용 제한을 제외하면 내부는 물론, 외부의 워드프레스 및 워드프레스가 아닌 시스템의 데이터도 요청할 수 있습니다. HTTP API, Ajax API, 자바스크립트 조합으로도 예제에서 REST API로 구성한 콘텐츠 출력이 가능하므로 하나의 방식이 아니라 상황에 따른 효율적 방식을 선택해야 합니다.

워드프레스 REST API 관련하여 예제에서 안내하지 못한 것도 있지만, 해당 API를 실제 웹사이트에서 사용한다면 코덱스를 먼저 찾아 개략적인 내용과 흐름을 이해하기 바랍니다.

다음 링크의 이번 장 완성 파일을 받고 압축을 풀어 사이트 루트에 덮어쓰세요.

마치며

예제의 모든 구성 과정은 끝이며, 사이트 구성 과정의 필요로 설정하거나 설치한 요소를 제거합니다. 다음 순서에 따라 진행하세요.

wp-config.php

사이트 루트의 wp-config.php 파일에서 다음 코드 1번 줄을 찾아 2번 줄로 변경하고 저장합니다.

define('WP_DEBUG', true);
define('WP_DEBUG', false);

Query Monitor 플러그인 삭제

관리페이지 설치 플러그인 목록에서 Query Monitor 플러그인을 삭제합니다. 실제 예제 구성에서 활용한 때는 적었지만, 실제 사이트를 구성할 때 설치하면 도움이 되는 때가 많습니다.

연습장 제거

테마 루트 template-parts/navigation/navigation-top.php 파일에서 13번 줄 연습장 메뉴를 삭제합니다. 또, 관리페이지 페이지 목록에서 ‘_연습장’ page 포스트를 삭제하고, 테마의 연습장 페이지 템플릿 파일 _note.php 파일도 삭제합니다.

연재로 구성한 워드프레스 attachment 포스트 타입 이미지 콘텐츠 중심의 ‘고품격 고품질 워드프레스 무료 사진 저장소’ 완성 예제 사이트 구성은 모두 마칩니다.

예제 목차

0. 고품격 고품질 워드프레스 무료 사진 저장소

1. 예제 구성 환경과 파일

2. XAMPP, 워드프레스, 테마, 플러그인 설치와 설정

3. 테마 Pics Press

4. page 포스트 타입과 페이지 템플릿, 메뉴 구성

5. 워드프레스 핵심 용어 짚기

6. 워드프레스 포스트 타입 attachment

7. 워드프레스 이미지 사이즈

8. 워드프레스 이미지 사이즈 추가 및 변경

9. 워드프레스 이미지 파일 제어

10. 타입 attachment 템플릿과 image.php

11. 워드프레스 이미지 메타 데이터

12. GPS 데이터를 워드프레스 메타 데이터로 저장

13. 이미지 메타 데이터를 포스트 메타 데이터에 추가

14. Attachment 타입을 위한 워드프레스 커스텀 분류 등록

15. 이미지 메타 데이터를 워드프레스 분류와 필드 데이터에 저장

16. 이미지를 편집할 때 포스트 데이터와 메타 데이터 업데이트

17. 워드프레스 미디어 파일 업로드

18. 워드프레스 싱글 이미지 포스트 페이지

19. 워드프레스 아바타와 Author Archives

20. 워드프레스 이미지 사이즈별 데이터 출력

21. 워드프레스 폼 요소로 원하는 이미지 사이즈 다운로드

22. 워드프레스 텍스트 단락 및 줄 바꿈, wpautop

23. 워드프레스 사진의 EXIF 데이터 출력

24. 구글 지도에 표시하는 사진 촬영 위치

25. 워드프레스 attachment 포스트 타입의 아카이브

26. 워드프레스 함수로 자바스크립트 변수 데이터 생성

27. 워드프레스 커스텀 검색 – 쿼리 변수

28. 워드프레스 커스텀 검색 – 검색 폼과 쿼리 데이터

29. 워드프레스 커스텀 포스트 타입 ‘pic_album’

30. 커스텀 포스트 타입의 싱글 페이지

31. 워드프레스 WP_Query

32. 커스텀 쿼리, 페이지 템플릿, 포스트 아카이브

33. 분류 기준의 관련 포스트 커스텀 쿼리

34. wpdb 클래스로 구글 지도에 마커와 섬네일 표시

35. 워드프레스 분류 데이터 쿼리 클래스, WP_Term_Query

36. 워드프레스 템플릿 태그

37. 워드프레스 옵션 페이지, 옵션 필드

38. 워드프레스 사이트 프런트 페이지

39. 사이트 메뉴 및 포스트 페이지 링크

40. 워드프레스 Transient API

41. 워드프레스 분류의 term 데이터를 캐시 데이터로 생성

42. 워드프레스 역할 그룹과 권한으로 구성 요소 제어

43. 간단한 워드프레스 코멘트 폼 수정

44. 워드프레스 대시보드 위젯 추가

45. 워드프레스 REST API 간략 이해

46. 워드프레스 REST API 응답에 커스텀 필드 추가

47. 워드프레스 REST API 커스텀 라우트 및 엔드포인트

48. 워드프레스 REST API 커스텀 엔드포인트로 구글 클러스터 지도 마커와 인포 윈도 표시

49. 워드프레스 REST API, Underscore.js 자바스크립트 템플릿, 포스트 Ajax Load More

50. 워드프레스 REST API, Underscore.js 자바스크립트 템플릿, 코멘트 Ajax Load More

» 워드프레스 REST API 인증과 제한 및 제어