vapor-docs/docs/advanced/sessions.md

146 lines
5.4 KiB
Markdown

# Sessions
Sessions allow you to persist a user's data between multiple requests. Sessions work by creating and returning a unique cookie alongside the HTTP response when a new session is initialized. Browsers will automatically detect this cookie and include it in future requests. This allows Vapor to automatically restore a specific user's session in your request handler.
Sessions are great for front-end web applications built in Vapor that serve HTML directly to web browsers. For APIs, we recommend using stateless, [token-based authentication](../security/authentication.md) to persist user data between requests.
## Configuration
To use sessions in a route, the request must pass through `SessionsMiddleware`. The easiest way to achieve this is by adding this middleware globally.
```swift
app.middleware.use(app.sessions.middleware)
```
If only a subset of your routes utilize sessions, you can instead add `SessionsMiddleware` to a route group.
```swift
let sessions = app.grouped(app.sessions.middleware)
```
The HTTP cookie generated by sessions can be configured using `app.sessions.configuration`. You can change the cookie name and declare a custom function for generating cookie values.
```swift
// Change the cookie name to "foo".
app.sessions.configuration.cookieName = "foo"
// Configures cookie value creation.
app.sessions.configuration.cookieFactory = { sessionID in
.init(string: sessionID.string, isSecure: true)
}
```
By default, Vapor will use `vapor_session` as the cookie name.
## Drivers
Session drivers are responsible for storing and retrieving session data by identifier. You can create custom drivers by conforming to the `SessionDriver` protocol.
!!! warning
The session driver should be configured _before_ adding `app.sessions.middleware` to your application.
### In-Memory
Vapor utilizes in-memory sessions by default. In-memory sessions require zero configuration and do not persist between application launches which makes them great for testing. To enable in-memory sessions manually, use `.memory`:
```swift
app.sessions.use(.memory)
```
For production use cases, take a look at the other session drivers which utilize databases to persist and share sessions across multiple instances of your app.
### Fluent
Fluent includes support for storing session data in your application's database. This section assumes you have [configured Fluent](../fluent/overview.md) and can connect to a database. The first step is to enable the Fluent sessions driver.
```swift
import Fluent
app.sessions.use(.fluent)
```
This will configure sessions to use the application's default database. To specify a specific database, pass the database's identifier.
```swift
app.sessions.use(.fluent(.sqlite))
```
Finally, add `SessionRecord`'s migration to your database's migrations. This will prepare your database for storing session data in the `_fluent_sessions` schema.
```swift
app.migrations.add(SessionRecord.migration)
```
Make sure to run your application's migrations after adding the new migration. Sessions will now be stored in your application's database allowing them to persist between restarts and be shared between multiple instances of your app.
### Redis
Redis provides support for storing session data in your configured Redis instance. This section assumes you have [configured Redis](../redis/overview.md) and can send commands to the Redis instance.
To use Redis for Sessions, select it when configuring your application:
```swift
import Redis
app.sessions.use(.redis)
```
This will configure sessions to use the Redis sessions driver with the default behavior.
!!! seealso
Refer to [Redis → Sessions](../redis/sessions.md) for more detailed information about Redis and Sessions.
## Session Data
Now that sessions are configured, you are ready to persist data between requests. New sessions are initialized automatically when data is added to `req.session`. The example route handler below accepts a dynamic route parameter and adds the value to `req.session.data`.
```swift
app.get("set", ":value") { req -> HTTPStatus in
req.session.data["name"] = req.parameters.get("value")
return .ok
}
```
Use the following request to initialize a session with the name Vapor.
```http
GET /set/vapor HTTP/1.1
content-length: 0
```
You should receive a response similar to the following:
```http
HTTP/1.1 200 OK
content-length: 0
set-cookie: vapor-session=123; Expires=Fri, 10 Apr 2020 21:08:09 GMT; Path=/
```
Notice the `set-cookie` header has been added automatically to the response after adding data to `req.session`. Including this cookie in subsequent requests will allow access to the session data.
Add the following route handler for accessing the name value from the session.
```swift
app.get("get") { req -> String in
req.session.data["name"] ?? "n/a"
}
```
Use the following request to access this route while making sure to pass the cookie value from the previous response.
```http
GET /get HTTP/1.1
cookie: vapor-session=123
```
You should see the name Vapor returned in the response. You can add or remove data from the session as you see fit. Session data will be synchronized with the session driver automatically before returning the HTTP response.
To end a session, use `req.session.destroy`. This will delete the data from the session driver and invalidate the session cookie.
```swift
app.get("del") { req -> HTTPStatus in
req.session.destroy()
return .ok
}
```