-
Notifications
You must be signed in to change notification settings - Fork 67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cookie backed sessions #262
base: master
Are you sure you want to change the base?
Cookie backed sessions #262
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work @Jerben! 🎉
A few questions:
-
Since
Session.find
takes aRequest.t
andSession.set
takes aRequest.t
, what's the advantage of having a middleware that stores the sessions in the context? -
Sessions should probably come with a modular backend. I initially wanted to provide the cookie backend and the in-memory backend with Opium, and offer an API to allow users to implement their own backend. Does it make sense to do this as part of this PR?
-
The next step, once we have the sessions, will be to add a flash middleware. I think you've done this in Sihl already. Is the implementation in this PR taking this use case into account?
Thank for your quick feedback @tmattio
val find : string -> Request.t -> string option
val set : string * string option -> Response.t -> Response.t Usage could look like this in an Opium handler: ...
let user_id = Opium.Session.find "user_id" req in
(* doing something with the user, then logging out *)
Opium.Response.of_plain_text "" |> Opium.Session.set ("user_id", None) |> Lwt.return
Good point. For Sihl I think we will have the cookie based session management enabled by defaults since it's stateless. So far we have been using MariaDB and Postgres backends as default. Play suggests to take care of session data that is big (> 4 KB) or sensitive yourself. With this PR we could easily add other backends as separate middlewares like
Yes that is planned :) We already have a session based flash middleware in Sihl, but my plan was to submit a cookie based flash message implementation for Opium and switch to that. The flash message cookie doesn't have to be signed. We could still implement a session based flash message middleware next to each other if the payload size limit or performance impact is an issue, but use this as default because it is stateless and has no dependencies. (https://www.playframework.com/documentation/2.8.x/JavaSessionFlash#Flash-scope) We want to improve the out-of-box experience with Sihl and having those two middlewares with cookie based implementation is a good first step. The API considers other implementations that can be used for instance for performance reasons. Also we would like to contribute the CSRF and body parsing middlewares. |
That's what I meant, sorry. That's why I'm not sure to understand the need for the middleware - couldn't
In the PR,
Sounds great! |
You'd have to pass the |
My plan was to move |
I'm starting to think there's something obvious I'm not seeing, but: why couldn't the persistence happen in |
It could and maybe it should :) I am just using middlewares to swap implementations.. If you give me some more pointers I can try to come up with something else. |
I'm not against middlewares, but it does come with some drawbacks:
So I tend to prefer keeping things outside of middlewares when possible. In the case of sessions, I liked the design of https://github.com/inhabitedtype/ocaml-session (although admittedly I found the names of the functions confusing). We can't implement cookie backends with it, but we could take some inspiration from it. If we want to hide the functors from users, we could imagine an API like this: let (module User_session) = Opium.Session.signed_cookie ~signer:Config.user_session_signer
(* In the handler *)
User_session.get "_session" request Or, if we accept to require users to have to set their app for sessions to work: Opium.Session.set_default_signer signer
(* In the handler *)
Opium.Session.Cookie.get "_session" request |
That being said, most frameworks I have used require a middleware for sessions to work, I'm failing to understand the reasoning behind it. |
379c757
to
6ea6d55
Compare
I updated the PR and contributed some tests that shows the usage. I agree with the limitations of middlewares. This is a simple way to associate 4KB of data to a user session. It is completely up to the user to store a reference such as All you need to understand to use Opium are |
We could also read from |
Is this still being worked on? |
We implemented this downstream, it should be straightforward to use that. I am a bit out of the loop, especially regarding the switch back to cohttp. @rgrinberg How would that impact the request/response API? If there is interest I could update this PR to use Sihl's implementation. |
That would be useful for sure. |
This is just a draft of cookie backed sessions based on how the Play framework does it. (https://www.playframework.com/documentation/2.8.x/JavaSessionFlash).
It needs tests and some more thought before it can be merged.