diff --git a/ecrire/action/redirect.php b/ecrire/action/redirect.php
index 5b908fb7a9b1d2a4e67666e5339bf16d502a671d..371f3b0c760e0782541ddfccb43cafcb71a1b59e 100644
--- a/ecrire/action/redirect.php
+++ b/ecrire/action/redirect.php
@@ -38,50 +38,92 @@ if (!defined('_ECRIRE_INC_VERSION')) {
 function action_redirect_dist() {
 	$type = _request('type');
 	$id = intval(_request('id'));
+	$page = false;
 
-	if ($m = _request('var_mode')) {
+	// verifier le type ou page transmis
+	if (!preg_match('/^\w+$/', $type)) {
+		$page = _request('page');
+		if (!preg_match('/^\w+$/', $page)) {
+			return;
+		}
+	}
+
+	if ($var_mode = _request('var_mode')) {
 		// forcer la mise a jour de l'url de cet objet !
 		if (!defined('_VAR_URLS')) {
 			define('_VAR_URLS', true);
 		}
 	}
 
-	if (preg_match('/^\w+$/', $type)) {
-		$h = generer_url_entite_absolue($id, $type, '', '', true);
+	if ($page) {
+		$url = generer_url_public($page, '', true);
 	} else {
-		if ($page = _request('page')
-			and preg_match('/^\w+$/', $page)
+		$url = calculer_url_redirect_entite($type, $id, $var_mode);
+	}
+
+	$status = '302';
+	if ($url) {
+		if ($var_mode) {
+			$url = parametre_url($url, 'var_mode', $var_mode);
+		}
+
+		if ($var_mode == 'preview'
+			and defined('_PREVIEW_TOKEN')
+			and _PREVIEW_TOKEN
+			and autoriser('previsualiser')
 		) {
-			$h = generer_url_public($page, '', true);
-		} else {
-			return;
+			include_spip('inc/securiser_action');
+			$token = calculer_token_previsu($url);
+			$url = parametre_url($url, 'var_previewtoken', $token);
 		}
-	}
 
-	if ($m > '') {
-		$h = parametre_url($h, 'var_mode', $m);
+		if (_request('status') and _request('status') == '301') {
+			$status = '301';
+		}
+	} else {
+		$url = generer_url_public('404', '', true);
 	}
 
-	if ($m == 'preview'
-		and defined('_PREVIEW_TOKEN')
-		and _PREVIEW_TOKEN
-		and $type
-		and $id
-		and autoriser('previsualiser')
-	) {
-		include_spip('inc/securiser_action');
-		$token = calculer_token_previsu($type, $id);
-		$h = parametre_url($h, 'var_previewtoken', $token);
+	redirige_par_entete(str_replace('&', '&', $url), '', $status);
+}
+
+/**
+ * Retourne l’URL de l’objet sur lequel on doit rediriger
+ *
+ * On met en cache les calculs (si memoization),
+ * et on ne donne pas l’URL si la personne n’y a pas accès
+ *
+ * @param string $type
+ * @param int $id
+ * @param string $var_mode
+ */
+function calculer_url_redirect_entite($type, $id, $var_mode) {
+	// invalider le cache à chaque modif en bdd
+	$date = 0;
+	if (isset($GLOBALS['meta']['derniere_modif'])) {
+		$date = $GLOBALS['meta']['derniere_modif'];
 	}
+	$key = "url-$date-$type-$id";
 
-	$status = '302';
-	if (_request('status') and _request('status') == '301') {
-		$status = '301';
+	// Obtenir l’url et si elle est publié du cache memoization
+	if (function_exists('cache_get') and $desc = cache_get($key)) {
+		list($url, $publie) = $desc;
+	}
+	// Si on ne l’a pas trouvé, ou si var mode, on calcule l’url et son état publie
+	if (!$desc or $var_mode) {
+		$publie = objet_test_si_publie($type, $id);
+		$url = generer_url_entite_absolue($id, $type, '', '', true);
+		if (function_exists('cache_set')) {
+			cache_set($key, array($url, $publie), 3600);
+		}
 	}
 
-	if ($h) {
-		redirige_par_entete(str_replace('&', '&', $h), '', $status);
-	} else {
-		redirige_par_entete('/', '', $status);
+	// On valide l’url si elle est publiee ; sinon si preview on teste l’autorisation
+	if ($publie) {
+		return $url;
+	} elseif (defined('_VAR_PREVIEW') and _VAR_PREVIEW and autoriser('voir', $type, $id)) {
+		return $url;
 	}
-}
+
+	return;
+}
\ No newline at end of file
diff --git a/ecrire/inc/securiser_action.php b/ecrire/inc/securiser_action.php
index 4bbebfbc1bed0b9302a136131688d03497dbcc75..8fcbed6d418ead890468f78594f740957e3a1176 100644
--- a/ecrire/inc/securiser_action.php
+++ b/ecrire/inc/securiser_action.php
@@ -301,13 +301,12 @@ function verifier_cle_action($action, $cle) {
  * pour qu’une personne tierce le relise. Valable quelques temps.
  *
  * @see verifier_token_previsu()
- * @param string $type Type d’objet
- * @param int $id_objet Identifiant de l’objet
+ * @param string $url Url à autoriser en prévisu
  * @param int|null id_auteur qui génère le token de prévisu. Null utilisera auteur courant.
  * @param string $alea Nom de l’alea à utiliser
  * @return string Token, de la forme "{id}*{hash}"
  */
-function calculer_token_previsu($type, $id_objet, $id_auteur = null, $alea = 'alea_ephemere') {
+function calculer_token_previsu($url, $id_auteur = null, $alea = 'alea_ephemere') {
 	if (is_null($id_auteur)) {
 		if (!empty($GLOBALS['visiteur_session']['id_auteur'])) {
 			$id_auteur = $GLOBALS['visiteur_session']['id_auteur'];
@@ -316,7 +315,10 @@ function calculer_token_previsu($type, $id_objet, $id_auteur = null, $alea = 'al
 	if (!$id_auteur = intval($id_auteur)) {
 		return "";
 	}
-	$token = _action_auteur('previsualiser-' . $type . '-' . $id_objet, $id_auteur, null, $alea);
+	// On nettoie l’URL de tous les var_.
+	$url = nettoyer_uri_var($url);
+
+	$token = _action_auteur('previsualiser-' . $url, $id_auteur, null, $alea);
 	return "$id_auteur-$token";
 }
 
@@ -338,8 +340,7 @@ function verifier_token_previsu($token) {
 	// retrouver auteur / hash
 	$e = explode('-', $token, 2);
 	if (count($e) == 2 and is_numeric(reset($e))) {
-		list($id_auteur, $hash) = $e;
-		$id_auteur = intval($id_auteur);
+		$id_auteur = intval(reset($e));
 	} else {
 		return false;
 	}
@@ -347,22 +348,12 @@ function verifier_token_previsu($token) {
 	// calculer le type et id de l’url actuelle
 	include_spip('inc/urls');
 	include_spip('inc/filtres_mini');
-	$self = url_absolue(self());
-	$contexte = urls_decoder_url($self);
-	list($type, $contexte) = $contexte;
-	if (is_numeric($type)) {
-		return false;
-	}
-	$_id_table = id_table_objet($type);
-	if (empty($contexte[$_id_table])) {
-		return false;
-	}
-	$id = $contexte[$_id_table];
+	$url = url_absolue(self());
 
 	// verifier le token
-	$_token = calculer_token_previsu($type, $id, $id_auteur, 'alea_ephemere');
+	$_token = calculer_token_previsu($url, $id_auteur, 'alea_ephemere');
 	if (!$_token or $token !== $_token) {
-		$_token = calculer_token_previsu($type, $id, $id_auteur, 'alea_ephemere_ancien');
+		$_token = calculer_token_previsu($url, $id_auteur, 'alea_ephemere_ancien');
 		if (!$_token or $token !== $_token) {
 			return false;
 		}
@@ -370,8 +361,6 @@ function verifier_token_previsu($token) {
 
 	return array(
 		'id_auteur' => $id_auteur,
-		'type' => $type,
-		'id_objet' => $id
 	);
 }
 
diff --git a/ecrire/inc/utils.php b/ecrire/inc/utils.php
index 7610de0d5864ae0029750729546b14190d595da2..57afa33e78f011e54aa479b7351b2ff019894dee 100644
--- a/ecrire/inc/utils.php
+++ b/ecrire/inc/utils.php
@@ -591,15 +591,22 @@ function nettoyer_uri($reset = null) {
 		return $propre;
 	}
 	$done = true;
+	return $propre = nettoyer_uri_var($GLOBALS['REQUEST_URI']);
+}
 
-	$uri1 = $GLOBALS['REQUEST_URI'];
+/**
+ * Nettoie une request_uri des paramètres var_xxx
+ * @param $request_uri
+ * @return string
+ */
+function nettoyer_uri_var($request_uri) {
+	$uri1 = $request_uri;
 	do {
 		$uri = $uri1;
 		$uri1 = preg_replace(',([?&])(PHPSESSID|(var_[^=&]*))=[^&]*(&|$),i',
 			'\1', $uri);
 	} while ($uri <> $uri1);
-
-	return $propre = (preg_replace(',[?&]$,', '', $uri1));
+	return preg_replace(',[?&]$,', '', $uri1);
 }