url-rewriting – URL única cada vez

Pregunta:

He creado una pequeña herramienta de búsqueda que, a menos que conozca el código EXACTO, no será llevado a la publicación. Por ejemplo, si escribo "OI812", me llevará a un tipo de publicación personalizada que es ../CPT/OI812.

El CPT no es parte de la búsqueda normal y eliminé cualquier cosa con esa babosa de un redireccionamiento canónico. A menos que utilicen mi pequeña herramienta de búsqueda e ingresen el código exactamente, no los llevará a la página.

Hasta ahora tan bueno. Sin embargo, me gustaría tener una URL generada de forma única cada vez que acceden a la página. EG ../CPT/HASHorSOMETHINGcrazyANDrandom. Esto haría que compartir la URL sea inútil a menos que visiten la página e ingresen el código en la herramienta de búsqueda.

Tengo curiosidad por saber cómo se haría uno con esto. He buscado por todas partes, pero los términos de búsqueda para algo como esto parecen ser un poco ubicuos. Se agradece cualquier ayuda.

Respuesta:

Puede usar una implementación parcial de JWT para pasar un token único que incluya información de identificación y la ID de publicación solicitada (o slug) como punto final, y verificar la información de identificación después de la validación.

Las URL que contienen un token único se pueden reescribir para pasar el token como una variable específica. Un gancho de acción 'parse_query' puede verificar la presencia de la variable del token y reemplazar la consulta con una que devolverá la publicación adecuada si el token es válido, o un error si no lo es.

De esta manera, solo el visitante que emitió el token podría usarlo para acceder a la publicación (a menos que otra persona adquiera el token y falsifique la IP del visitante original; esto podría protegerse aún más con una cookie o ID de sesión de algún tipo). Forjar fichas es imposible sin tu secreto.

$secret           = '{insert randomly generated string here}';
$custom_post_type = 'my_cpt';
$unique_url_base  = 'cpt';

add_action( 'init', 'wpse_212309_rewrite_unique_token_url' );

/**
 * Adds a rewrite rule to forward URLs in the format /cpt/{unique token} to
 * index.php?post_type=my_cpt&unique_token={unique token}. Supersedes WordPress
 * rewrites for the endpoint.
 **/
function wpse_212309_rewrite_unique_token_url(){
    add_rewrite_rule(
        trailingslashit( $unique_url_base ) . '([^\.]*.[^\.]*)$',
        'index.php?post_type=' . $custom_post_type . '&unique_token=$matches[1]',
        'top'
    );
}

add_action( 'parse_query', 'wpse_212309_decode_unique_token_query' );

/**
 * Replaces queries for the 'my_cpt' post-type containing a unique token with
 * the appropriate 'my_cpt' post if the token is valid (i.e., passed to the
 * server from the client IP to which it was assigned).
 **/
function wpse_212309_decode_unique_token_query( $wp ) {
    if( is_admin() )
        return;

    if( isset( $wp->query_vars[ 'p' ] ) || $custom_post_type != $wp->query_vars[ 'post_type' ] || empty( $_GET[ 'unique_token' ] ) )
        return;

    $post_id = wpse_212309_get_post_id_from_unique_slug( $_GET[ 'unique_token' ] );

    if( ! $post_id ) {
        $wp->set_404();
        status_header( 404 );
        return;
    }

    $wp->parse_request( 'p=' . $post_id );
}

/**
 * Encodes data into a URL-friendly JWT-esque token including IP information
 * for the requesting party, as well as an optional expiration timestamp.
 **/
function wpse_212309_encode_token( $payload, $expiration = null ) {    
    $payload[ 'aud' ] = hash( 'md5', $_SERVER[ 'REMOTE_ADDR' ] . $_SERVER[ 'HTTP_X_FORWARDED_FOR' ] );
    $payload[ 'iss' ] = time();

    if( isset( $expiration ) )
        $payload[ 'exp' ] = $expiration;

    $payload = base64_encode( json_encode( $payload ) );
    $hash    = hash( 'md5', $payload . $secret );

    return urlencode( $payload . '.' . $hash );
}

/**
 * Decodes a token generated by 'wpse_212309_encode_token()', returning the
 * payload if the token is both unaltered and sent by the original client IP
 * or false otherwise.
 **/
function wpse_212309_decode_token( $token ) {
    if( empty( $token ) || -1 === strpos( $token, '.' ) )
        return false;

    $token   = urldecode( $token );
    $token   = explode( '.', $token );
    $hash    = $token[1];
    $payload = $token[0];

    // If the payload or the hash is missing, the token's invalid.
    if( empty( $payload ) || empty( $hash ) )
        return false;

    $hash_check = hash( 'md5', $payload . $secret );

    // Has the payload and/or hash been modified since the token was issued?
    if( $hash_check !== $hash )
        return false;

    $payload = base64_decode( $payload );

    if( ! $payload )
        return false;

    $payload = json_decode( $payload, true );

    if( ! $payload )
        return false;

    $audience_check = hash( 'md5', $_SERVER[ 'REMOTE_ADDR' ] . $_SERVER[ 'HTTP_X_FORWARDED_FOR' ] );

    // Was this token passed to the server by the IP that it was issued to?
    if( $audience_check != $payload[ 'aud' ] )
        return false;

    // Does the payload have an expiration date - if so, has it expired?
    if( ! empty( $payload[ 'exp' ] ) && $payload[ 'exp' ] > time() )
        return false;

    // Token validated - return the payload as legitimate data.
    return $payload;
}

/**
 * Produces a token associating a post ID with a particular client, suitable
 * for inclusion in a URL. Optionally takes a "time to live" argument, in
 * in seconds, before the token should expire.
 **/
function wpse_212309_generate_unique_slug( $post_id, $ttl = null ) {
    $expiration = null;

    if( $ttl )
        $expiration = time() + $ttl * 1000;

    return wpse_212309_encode_token( array( 'pid' => $post_id ), $expiration );
}

/**
 * Returns a post ID from a token if the token was in fact issued to the 
 * requesting client IP, or false otherwise.
 **/
function wpse_212309_get_post_id_from_unique_slug( $token ) {
    $payload = wpse_212309_decode_token( $token );

    if( ! $payload )
        return false;

    return $payload[ 'pid' ];
}

La forma en que realmente envía visitantes a las URL únicas que contienen un token depende de su aplicación (es decir, cómo configura su "herramienta de búsqueda"), pero con la implementación anterior puede recuperar un slug exclusivo de visitante para una ID de publicación como esta:

// A slug that only works for the visitor it was issued to:
$unique_slug = wpse_212309_generate_unique_slug( $post_id );

// OR, for one that additionally expires in an hour:
$unique_slug = wpse_212309_generate_unique_slug( $post_id, 3600 )

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top

web tasarım