[英]How can I share sessions between actix-session and a PHP application when using Redis as session storage?
I want to switch my PHP website using Redis as session storage to actix-web. 我想将使用Redis作为会话存储的PHP网站切换到actix-web。 The only problem I've encountered is sharing sessions between my subdomains. 我遇到的唯一问题是在我的子域之间共享会话。 I have many services and only some of them will get switched to Rust. 我有很多服务,只有其中一些会切换到Rust。
A crate already exists for sessions : 用于会议的板条箱已存在 :
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()
}
My goal is to be able to read a Rust session from my PHP scripts. 我的目标是能够从我的PHP脚本读取Rust会话。
Here's what I've tried: 这是我尝试过的:
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();
And finally, I changed the default cookie: 最后,我更改了默认cookie:
setcookie( "mysession", "",1,"/" );
setcookie( "PHPSESSID", "",1,"/" );
I have no idea of the session format used in Rust and how to be able to share it with PHP. 我不知道Rust中使用的会话格式以及如何与PHP共享它。
actix-session serializes session data to JSON , signs the cookie and sets the name of the cookie to actix-session . actix-session将会话数据序列化为JSON , 对cookie进行签名,并将cookie 的名称设置为actix-session 。
To verify, run the minimal cookie-session-example and do a request with curl: 要进行验证,请运行最小的cookie-session-example并使用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
Decoding with decodeURIComponent
gives: 使用解码decodeURIComponent
解码可得出:
> decodeURIComponent("ZTe%2Fb%2F085+VQcxL%2FQRKCnldUxzoc%2FNEOQe94PTBGUfc%3D%7B%22counter%22%3A%221%22%7D")
'ZTe/b/085+VQcxL/QRKCnldUxzoc/NEOQe94PTBGUfc={"counter":"1"}'
As far as I know, ZTe/b/085+VQcxL/QRKCnldUxzoc/NEOQe94PTBGUfc=
is the signature. 据我所知, ZTe/b/085+VQcxL/QRKCnldUxzoc/NEOQe94PTBGUfc=
是签名。
This is probably not what your PHP script is doing, so you might want to use HttpRequest::headers
directly. 这可能不是您的PHP脚本在做什么,因此您可能想直接使用HttpRequest::headers
。 For example, by creating your own Session
type, then using that type in your handlers: 例如,通过创建自己的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"))
}
}
Result (irrelevant headers removed for brevity): 结果(为简洁起见,删除了不相关的标题):
$ 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⏎
You may also observe the results in a browser, urls http://localhost:8000/set and http://localhost:8000/get . 您还可以在浏览器中观察结果,网址为http:// localhost:8000 / set和http:// localhost:8000 / get 。
This is quite simplistic, but gives you full control over the session cookies. 这非常简单,但是可以完全控制会话cookie。
NOTE: The solution above does nothing to secure the cookies. 注意:上面的解决方案不能保护cookie。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.