Skip to content

Commit 9f51e1f

Browse files
committed
Session API: redo JWTSessionStore + doc
1 parent 480ec68 commit 9f51e1f

File tree

11 files changed

+516
-296
lines changed

11 files changed

+516
-296
lines changed

TODO

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,5 @@
33
* make reset headers on error configurable
44
* netty reports a leak in MVC body
55

6-
* doc Session
76
* doc WebSocket
8-
* doc FileUpload change
97
* doc ContextParam/SessionParam

docs/asciidoc/session.adoc

Lines changed: 286 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,302 @@
22

33
Session is accessible via
44

5-
- javadoc::Context[sessionOrNull]: which find an existing session
6-
- javadoc::Context[session]: which find an existing session or create a new one
5+
- javadoc:Context[sessionOrNull]: which find an existing session
6+
- javadoc:Context[session]: which find an existing session or create a new one
77
88
Sessions have a lot of uses cases but the most commons are: authentication, storing information
99
about current user, etc.
1010

1111
A session attribute must be a String or a primitive. The session doesn't allow storing of arbitrary
1212
objects. It's intended as a simple mechanism to store basic data (not an object graph).
1313

14-
Jooby provides two javadoc::SessionStore[] implementation:
14+
Jooby provides the following javadoc::SessionStore[]:
1515

1616
- In-Memory sessions - which you should combine with an a sticky sessions proxy if you plan to run multiple instances.
1717
- Cookie sessions signed with a secret key
18+
- JSON Web Token sessions
1819
19-
=== Working with Sessions
20+
=== In-Memory Session
2021

22+
Default session store uses memory to save session data. This store:
2123

24+
- Uses a cookie/header to read/save the session ID
25+
- Store session data in-memory
26+
27+
.In-Memory Session
28+
[source,java,role="primary"]
29+
----
30+
{
31+
get("/", ctx -> {
32+
Session session = ctx.session(); // <1>
33+
34+
session.put("foo", "bar"); // <2>
35+
36+
return session.get("foo").value(); // <3>
37+
});
38+
}
39+
----
40+
41+
.Kotlin
42+
[source,kotlin,role="secondary"]
43+
----
44+
{
45+
get("/") {
46+
val session = ctx.session() // <1>
47+
48+
session.put("foo", "bar") // <2>
49+
50+
session.get("foo").value() // <3>
51+
}
52+
}
53+
----
54+
55+
<1> Find an existing session or create a new session
56+
<2> Set a session attribute
57+
<3> Get a session attribute
58+
59+
Session token/ID is retrieved it from request cookie. Default session cookie is javadoc::SessionToken[SID, text=jooby.sid]. To customize cookie details:
60+
61+
.In-Memory Session with Custom Cookie
62+
[source,java,role="primary"]
63+
----
64+
{
65+
setSessionStore(SessionStore.memory(new Cookie("SESSION"))); // <1>
66+
67+
get("/", ctx -> {
68+
Session session = ctx.session();
69+
70+
session.put("foo", "bar");
71+
72+
return session.get("foo").value();
73+
});
74+
}
75+
----
76+
77+
.Kotlin
78+
[source,kotlin,role="secondary"]
79+
----
80+
{
81+
sessionStore = SessionStore.memory(Cookie("SESSION")) // <1>
82+
83+
get("/") {
84+
val session = ctx.session()
85+
86+
session.put("foo", "bar")
87+
88+
session.get("foo").value()
89+
}
90+
}
91+
----
92+
93+
<1> Set an `in-memory` session store with a custom cookie named: `SESSION`
94+
95+
Alternative you can use a request header to retrieve a session token/ID:
96+
97+
.In-Memory Session with HTTP Header
98+
[source,java,role="primary"]
99+
----
100+
{
101+
setSessionStore(SessionStore.memory(SessionToken.header("TOKEN"))); // <1>
102+
103+
get("/", ctx -> {
104+
Session session = ctx.session();
105+
106+
session.put("foo", "bar");
107+
108+
return session.get("foo").value();
109+
});
110+
}
111+
----
112+
113+
.Kotlin
114+
[source,kotlin,role="secondary"]
115+
----
116+
{
117+
sessionStore = SessionStore.memory(SessionToken.header("TOKEN")) // <1>
118+
119+
get("/") {
120+
val session = ctx.session()
121+
122+
session.put("foo", "bar")
123+
124+
session.get("foo").value()
125+
}
126+
}
127+
----
128+
129+
<1> Session Token/ID comes from HTTP header `TOKEN`
130+
131+
You can mix cookie and header tokens:
132+
133+
.Java
134+
[source,java,role="primary"]
135+
----
136+
{
137+
setSessionStore(SessionStore.memory(SessionToken.comibe(SessionToken.cookie("SESSION"), SessionToken.header("TOKEN")))); // <1>
138+
139+
get("/", ctx -> {
140+
Session session = ctx.session();
141+
142+
session.put("foo", "bar");
143+
144+
return session.get("foo").value();
145+
});
146+
}
147+
----
148+
149+
.Kotlin
150+
[source,kotlin,role="secondary"]
151+
----
152+
{
153+
sessionStore = SessionStore.memory(SessionToken.combie(SessionToken.cookie("SESSION"), SessionToken.header("TOKEN"))) // <1>
154+
155+
get("/") {
156+
val session = ctx.session()
157+
158+
session.put("foo", "bar")
159+
160+
session.get("foo").value()
161+
}
162+
}
163+
----
164+
165+
<1> Session Token/ID comes from HTTP Cookie `SESSION` or HTTP header `TOKEN` (in that order)
166+
167+
=== Signed Session
168+
169+
This is a stateless session store that expects to find session token on each request. The server doesn't keep any state.
170+
171+
- Session data is retrieve/save from/into HTTP Cookie or Header
172+
- Session data is (un)signed with `HmacSHA256`. Key must be 256 bits long (32 bytes)
173+
174+
Data sign/unsign is done using javadoc:Cookie[sign, java.lang.String, java.lang.String] and javadoc:Cookie[unsign, java.lang.String, java.lang.String].
175+
176+
.Usage
177+
[source,java,role="primary"]
178+
----
179+
{
180+
String secret = "super secret key"; // <1>
181+
182+
setSessionStore(SessionStore.signed(secret)); // <2>
183+
184+
get("/", ctx -> {
185+
Session session = ctx.session();
186+
187+
session.put("foo", "bar");
188+
189+
return session.get("foo").value();
190+
});
191+
}
192+
----
193+
194+
.Kotlin
195+
[source,kotlin,role="secondary"]
196+
----
197+
{
198+
val secret = "super secret key" // <1>
199+
200+
sessionStore = SessionStore.signed(secret) // <2>
201+
202+
get("/") {
203+
val session = ctx.session()
204+
205+
session.put("foo", "bar")
206+
207+
session.get("foo").value()
208+
}
209+
}
210+
----
211+
212+
<1> A secret key is required to signed the data
213+
<2> Creates a cookie session store using the secret
214+
215+
Like with `memory` session store you can use HTTP headers:
216+
217+
.Signed with headers
218+
[source,java,role="primary"]
219+
----
220+
{
221+
String secret = "super secret key"; // <1>
222+
223+
setSessionStore(SessionStore.signed(secret, SessionToken.header("TOKEN"))); // <2>
224+
225+
get("/", ctx -> {
226+
Session session = ctx.session();
227+
228+
session.put("foo", "bar");
229+
230+
return session.get("foo").value();
231+
});
232+
}
233+
----
234+
235+
.Kotlin
236+
[source,kotlin,role="secondary"]
237+
----
238+
{
239+
val secret = "super secret key" // <1>
240+
241+
sessionStore = SessionStore.signed(secret, SessionToken.header("TOKEN")) // <2>
242+
243+
get("/") {
244+
val session = ctx.session()
245+
246+
session.put("foo", "bar")
247+
248+
session.get("foo").value()
249+
}
250+
}
251+
----
252+
253+
=== JWT Session
254+
255+
The javadoc:JWTSession[] session store works it also a stateless session that
256+
uses https://jwt.io[JSON Web Token] standard to decode/encode data.
257+
258+
To use the javadoc:JWTSession[] session store you need to add the `jooby-jwt` dependency:
259+
260+
[dependency, artifactId="jooby-jwt"]
261+
.
262+
263+
.JWT Session
264+
[source,java,role="primary"]
265+
----
266+
267+
import io.jooby.session.JWTSession;
268+
269+
{
270+
String secret = "super secret key"; // <1>
271+
272+
setSessionStore(new JWTSession(secret)); // <2>
273+
274+
get("/", ctx -> {
275+
Session session = ctx.session();
276+
277+
session.put("foo", "bar");
278+
279+
return session.get("foo").value();
280+
});
281+
}
282+
----
283+
284+
.Kotlin
285+
[source,kotlin,role="secondary"]
286+
----
287+
288+
import io.jooby.session.JWTSession
289+
290+
{
291+
val secret = "super secret key" // <1>
292+
293+
sessionStore = JWTSession(secret) // <2>
294+
295+
get("/") {
296+
val session = ctx.session()
297+
298+
session.put("foo", "bar")
299+
300+
session.get("foo").value()
301+
}
302+
}
303+
----

0 commit comments

Comments
 (0)