mirror of https://github.com/vapor/docs.git
143 lines
3.2 KiB
Markdown
143 lines
3.2 KiB
Markdown
# Persisting Auth
|
|
|
|
Persisting authentication means that a user does not need to provide their credentials with every request.
|
|
This is useful for web apps where a user should only have to log in once.
|
|
|
|
!!! note
|
|
For APIs, it's recommended that the user send a token with every request.
|
|
See [Getting Started](getting-started.md) for an example about Token auth.
|
|
|
|
|
|
## Sessions
|
|
|
|
Sessions are built into Vapor by default and are an easy way to persist users in your web app.
|
|
|
|
### SessionPersistable
|
|
|
|
The first step is to conform your user model to the `SessionPersistable` protocol.
|
|
|
|
```swift
|
|
import AuthProvider
|
|
|
|
extension User: SessionPersistable {}
|
|
```
|
|
|
|
If your user is a Model, the protocol methods will be implemented automatically. However,
|
|
you can implement them if you want to do something custom.
|
|
|
|
```swift
|
|
import AuthProvider
|
|
import HTTP
|
|
|
|
extension User: SessionPersistable {
|
|
func persist(for: Request) throws {
|
|
// something custom
|
|
}
|
|
|
|
static func fetchPersisted(for: Request) throws -> Self? {
|
|
// something custom
|
|
}
|
|
}
|
|
|
|
```
|
|
|
|
### Middleware
|
|
|
|
Now that the user is `SessionPersistable`, we can create our middleware.
|
|
|
|
#### Sessions
|
|
|
|
First let's start by creating `SessionMiddleware`. We'll use the `MemorySessions()` to get started.
|
|
|
|
```swift
|
|
let memory = MemorySessions()
|
|
let sessionsMiddleware = SessionsMiddleware(memory)
|
|
```
|
|
|
|
#### Persist
|
|
|
|
Now let's create the `PersistMiddleware`. This will take care of persisting our user once they've
|
|
been authenticated.
|
|
|
|
```swift
|
|
let persistMiddleware = PersistMiddleware(User.self)
|
|
```
|
|
|
|
Since our user conforms to `SessionPersistable` (and thus `Persistable`), we can pass it
|
|
into this middleware's init.
|
|
|
|
#### Authentication
|
|
|
|
Now to create the authentication middleware of your choice. We'll use `PasswordAuthenticationMiddleware`
|
|
which requires an `Authorization: Basic ...` header with the user's username and password.
|
|
|
|
|
|
```swift
|
|
let passwordMiddleware = PasswordAuthenticationMiddleware(User.self)
|
|
```
|
|
|
|
!!! note:
|
|
`User` must conform to `PasswordAuthenticatable` to be used with this middleware.
|
|
See the [Password](password.md) section to learn more.
|
|
|
|
### Droplet
|
|
|
|
Now we can create a Droplet and add all of our middleware.
|
|
|
|
```swift
|
|
import Vapor
|
|
import Sessions
|
|
import AuthProvider
|
|
|
|
let drop = try Droplet()
|
|
|
|
drop.middleware += [
|
|
sessionsMiddleware, persistMiddleware, passwordMiddleware
|
|
]
|
|
```
|
|
|
|
!!! seealso
|
|
If you only want to require authentication for certain routes, look at our
|
|
[Route Group](../routing/group.md) section in the routing docs.
|
|
|
|
|
|
### Route
|
|
|
|
Now you can add a route to return the authenticated user.
|
|
|
|
```swift
|
|
drop.get("me") { req in
|
|
// return the authenticated user
|
|
return try req.auth.assertAuthenticated(User.self)
|
|
}
|
|
```
|
|
|
|
### Request
|
|
|
|
Now we can make a request to our Vapor app.
|
|
|
|
```http
|
|
GET /me HTTP/1.1
|
|
Authorization: Basic dmFwb3I6Zm9v
|
|
```
|
|
|
|
!!! note
|
|
`dmFwb3I6Zm9v` is "vapor:foo" base64 encoded where "vapor" is the username and
|
|
"foo" is the password. This is the format of Basic authorization headers.
|
|
|
|
And we should get a response like.
|
|
|
|
```http
|
|
HTTP/1.1 200 OK
|
|
Content-Type: text/plain
|
|
Set-Cookie: vapor-session=...
|
|
|
|
```
|
|
|
|
Notice the `vapor-session` in the response. This can be used in subsequent requests instead of
|
|
the username and password.
|
|
|
|
|
|
|