Как я могу поделиться сессиями между actix-session и PHP-приложением при использовании Redis в качестве хранилища сессий? - PullRequest
1 голос
/ 08 июля 2019

Я хочу переключить свой PHP-сайт, используя Redis в качестве хранилища сеансов, на actix-web. Единственная проблема, с которой я столкнулся, - это совместное использование сеансов между моими поддоменами. У меня много служб, и только некоторые из них перейдут на Rust.

A ящик уже существует для сеансов :

use actix_session::{CookieSession, Session};
use actix_web::{web, App, Error, HttpResponse, HttpServer};

fn index(session: Session) -> Result<&'static str, Error> {
    // access session data
    if let Some(count) = session.get::<i32>("counter")? {
        println!("SESSION value: {}", count);
        session.set("counter", count + 1)?;
    } else {
        session.set("counter", 1)?;
    }

    Ok("Welcome!")
}

fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .wrap(
                CookieSession::signed(&[0; 32]) // <- create cookie based session middleware
                    .secure(false),
            )
            .service(web::resource("/").to(|| HttpResponse::Ok()))
    })
    .bind("127.0.0.1:59880")?
    .run()
}

Моя цель - прочитать сессию Rust из моих сценариев PHP.

Вот что я пробовал:

session_name('RustAndPHP'); // I don't have any idea to name the sessions in Rust

session_set_cookie_params(0,"/",".mydomainname.com",FALSE,FALSE);
setcookie(session_name(), session_id(),0,"/","mydomainname.com");
session_start();

И, наконец, я изменил файл cookie по умолчанию:

setcookie( "mysession", "",1,"/" );
setcookie( "PHPSESSID", "",1,"/" );

Я понятия не имею о формате сессии, используемом в Rust, и о том, как можно поделиться им с PHP.

1 Ответ

0 голосов
/ 12 июля 2019

actix-session сериализует данные сеанса в JSON , подписывает cookie , а устанавливает имя cookie в actix-session .

Чтобы проверить, запустите минимальный пример cookie-сессии и выполните запрос с помощью curl:

$ curl -v localhost:8080
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< content-length: 8
< content-type: text/plain; charset=utf-8
< set-cookie: actix-session=ZTe%2Fb%2F085+VQcxL%2FQRKCnldUxzoc%2FNEOQe94PTBGUfc%3D%7B%22counter%22%3A%221%22%7D; HttpOnly; Path=/
< date: Thu, 11 Jul 2019 21:22:38 GMT

Декодирование с помощью decodeURIComponent дает:

> decodeURIComponent("ZTe%2Fb%2F085+VQcxL%2FQRKCnldUxzoc%2FNEOQe94PTBGUfc%3D%7B%22counter%22%3A%221%22%7D")
'ZTe/b/085+VQcxL/QRKCnldUxzoc/NEOQe94PTBGUfc={"counter":"1"}'

Насколько я знаю, ZTe/b/085+VQcxL/QRKCnldUxzoc/NEOQe94PTBGUfc= является подписью.

Это, вероятно, не то, что делает ваш PHP-скрипт, поэтому вы можете использовать HttpRequest::headers напрямую.Например, создав свой собственный тип Session, затем используя этот тип в своих обработчиках:

use actix_web::{web, App, Error, HttpServer, HttpRequest, HttpResponse, FromRequest};
use actix_web::dev::Payload;
use actix_web::http::header::{COOKIE, SET_COOKIE};
use actix_web::error::ErrorUnauthorized;

fn main() {
    HttpServer::new(|| {
        App::new()
            .route("/set", web::to(set_cookie))
            .route("/get", web::to(get_cookie))
    })
    .bind("127.0.0.1:8000")
    .expect("Cannot bind to port 8000")
    .run()
    .expect("Unable to run server");
}

fn set_cookie() -> HttpResponse {
    HttpResponse::Ok()
        .header(SET_COOKIE, Session::cookie("0123456789abcdef"))
        .body("cookie set")
}

fn get_cookie(session: Session) -> HttpResponse {
    HttpResponse::Ok()
        .header(SET_COOKIE, Session::cookie("new_session_value"))
        .body(format!("Got cookie {}", &session.0))
}

struct Session(String);

impl Session {
    const COOKIE_NAME: &'static str = "my-session";

    fn cookie(value: &str) -> String {
        String::from(Self::COOKIE_NAME) + "=" + value
    }
}

impl FromRequest for Session {
    type Error = Error;
    type Future = Result<Self, Error>;
    type Config = ();

    fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future {
        for header in req.headers().get_all(COOKIE) {
            // check if header is UTF-8
            if let Ok(value) = header.to_str() {
                // split into cookie values
                for c in value.split(';').map(|s| s.trim()) {
                    // split at '='
                    if let Some(pos) = c.find('=') {
                        // is session key?
                        if Self::COOKIE_NAME == &c[0..pos] {
                            return Ok(Session(String::from(&c[(pos + 1)..])));
                        }
                    }
                }
            }
        }
        Err(ErrorUnauthorized("Session cookie missing"))
    }
}

Результат (для краткости неуместные заголовки удалены):

$ curl -v localhost:8000/get
< HTTP/1.1 401 Unauthorized
Session cookie missing⏎

$ curl -v localhost:8000/set
< HTTP/1.1 200 OK
< set-cookie: my-session=0123456789abcdef
cookie set⏎

$ curl -v --cookie my-session=0123456789abcdef localhost:8000/get
> Cookie: my-session=0123456789abcdef
>
< HTTP/1.1 200 OK
< set-cookie: my-session=new_session_value
Got cookie 0123456789abcdef⏎

Вы также можетенаблюдать результаты в браузере, URL http://localhost:8000/set и http://localhost:8000/get.

Это довольно упрощенно, но дает вам полный контроль над сессионными куки.

ПРИМЕЧАНИЕ: Решение, приведенное выше, никак не защищает файлы cookie.

...