强制对每个请求方法进行REST API身份验证

时间:2021-01-21 作者:km onur

WordPress端点默认规则,

GET               ----> PUBLIC
POST, PUT, DELETE ----> AUTH
如何强制验证WordPress REST APIGET 方法请求?

2 个回复
最合适的回答,由SO网友:Paul G. 整理而成

您不能直接根据请求是GET还是其他方式来应用身份验证,但如果您愿意,可以通过这种方式在全局范围内强制应用身份验证要求。

我已经非常详细地使用代码来说明发生了什么:

add_filter( \'rest_authentication_errors\', function ( $error ) {

    /**
     * If it\'s a WP_Error, leave it as is. Authentication failed anyway
     *
     * If it\'s true, then authentication has already succeeded. Leave it as-is.
     */
    if ( strtolower( $_SERVER[ \'REQUEST_METHOD\' ] ) === \'get\' && !is_wp_error( $error ) && $error !== true ) {

        if ( !is_user_logged_in() ) {
            $error = new \\WP_Error( \'User not logged-in\' );
        }
        
    }

    return $error;
}, 11 );
假设:

PHP至少是5.3版,我们只是在测试GET 请求如果在执行此筛选器之前遇到身份验证错误,则保留错误true, 这意味着身份验证已经成功,不需要阻止任何内容

SO网友:Jürgen Fink

这个问题问得好,但也不是那么容易(我花了一周时间才弄明白)。

然后我在WordPress文档中找到了两个很好的摘要:
Home / REST API Handbook / Extending the REST API / Routes and Endpoints
Home / REST API Handbook / Extending the REST API / Adding Custom Endpoints

在那里我发现了如何使用namespaces, routespermission_callback 正确地

关键部分是添加Permission Callback 进入function.php 你的主题。

/**
  * This is our callback function to return (GET) our data.
  *
  * @param WP_REST_Request $request This function accepts a rest request to process data.
  */
function get_your_data($request) {
    global $wpdb;
    $yourdata = $wpdb->get_results("SELECT * FROM your_custom_table");

    return rest_ensure_response( $yourdata );
};

/**
 * This is our callback function to insert (POST) new data record.
 *
 * @param WP_REST_Request $request This function accepts a rest request to process data.
 */
function insert_your_data($request) {
    global $wpdb;
    $contentType = isset($_SERVER["CONTENT_TYPE"]) ? trim($_SERVER["CONTENT_TYPE"]) : \'\';

    if ($contentType === "application/json") {
        $content = trim(file_get_contents("php://input"));
        $decoded = json_decode($content, true);
        $newrecord = $wpdb->insert( \'your_custom_table\', array( \'column_1\' => $decoded[\'column_1\'], \'column_2\' => $decoded[\'column_2\']));
    };
    if($newrecord){
        return rest_ensure_response($newrecord);
    }else{
        //something gone wrong
        return rest_ensure_response(\'failed\');
    };

    header("Content-Type: application/json; charset=UTF-8");
};
/**
 * This is our callback function to update (PUT) a data record.
 *
 * @param WP_REST_Request $request This function accepts a rest request to process data.
 */
function update_your_data($request) {
    global $wpdb;
    $contentType = isset($_SERVER["CONTENT_TYPE"]) ? trim($_SERVER["CONTENT_TYPE"]) : \'\';

    if ($contentType === "application/json") {
        $content = trim(file_get_contents("php://input"));
        $decoded = json_decode($content, true);
        $updatedrecord = $wpdb->update( \'your_custom_table\', array( \'column_1\' => $decoded[\'column_1\'], \'column_2\' => $decoded[\'column_2\']), array(\'id\' => $decoded[\'id\']), array( \'%s\' ));
    };

    if($updatedrecord){
        return rest_ensure_response($updatedrecord);
    }else{
        //something gone wrong
        return rest_ensure_response(\'failed\');
    };

    header("Content-Type: application/json; charset=UTF-8");
};

//  Permission Callback 
// \'ypp\' is the Prefix I chose (ypp = Your Private Page)

function ypp_get_private_data_permissions_check() {
    // Restrict endpoint to browsers that have the wp-postpass_ cookie.

    if ( !isset($_COOKIE[\'wp-postpass_\'. COOKIEHASH] )) {
       return new WP_Error( \'rest_forbidden\', esc_html__( \'OMG you can not create or edit private data.\', \'my-text-domain\' ), array( \'status\' => 401 ) );
    };
    // This is a black-listing approach. You could alternatively do this via white-listing, by returning false here and changing the permissions check.
    return true;
};

// And then add the permission_callback to your POST and PUT routes:

add_action(\'rest_api_init\', function() {
    /**
    * Register here your custom routes for your CRUD functions
    */
    register_rest_route( \'your_private_page/v1\', \'/data\', array(
       array(
          \'methods\'  => WP_REST_Server::READABLE,
          \'callback\' => \'get_your_data\',
          // Always allow.
          \'permission_callback\' => \'__return_true\' // <-- you can protect GET as well if your like
       ),
       array(
          \'methods\'  => WP_REST_Server::CREATABLE,
          \'callback\' => \'insert_your_data\',
          // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
          \'permission_callback\' => \'ypp_get_private_data_permissions_check\', // <-- that was the missing part
       ),
       array(
          \'methods\'  => WP_REST_Server::EDITABLE,
          \'callback\' => \'update_your_data\',
          // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
          \'permission_callback\' => \'ypp_get_private_data_permissions_check\', // <-- that was the missing part
       ),
    ));
});
如果您愿意,我会发布一个问题(与您的问题类似,但针对自定义路线),然后在回答中列出我的发现。

Full story 完整代码位于:
How to force Authentication on REST API for Password protected page using custom table and fetch() without Plugin

希望这有点帮助。

相关推荐

Execute shortcodes in PHP

我在帖子编辑器中添加了一个地理位置快捷码,可以根据用户的位置显示不同的信息,将其放在帖子页面的内容中,效果非常好。如何在主题的PHP文件中执行此短代码[地理位置][地理位置]?我正在使用免费修改Wordpress主题,我想添加一个新的<span>[geolocation][/geolocation]Information text content</span> 但在主题的内部。php文件,我如何才能做到这一点?如果我直接加上<span>[geolocation][/ge