Skip to content

Commit 5bd4baf

Browse files
committed
User token auth
1 parent 3f5ae8c commit 5bd4baf

File tree

10 files changed

+178
-1
lines changed

10 files changed

+178
-1
lines changed

Chapter 13/myProject/Sources/App/Modules/Blog/BlogRouter.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ struct BlogRouter: RouteCollection {
2828
postAdminController.setupRoutes(admin)
2929
categoryAdminController.setupRoutes(admin)
3030

31-
let api = routes.grouped("api")
31+
let api = routes
32+
.grouped(AuthenticatedUser.guardMiddleware())
33+
.grouped("api")
3234
postApiController.setupRoutes(api)
3335
categoryApiController.setupRoutes(api)
3436
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// File.swift
3+
//
4+
//
5+
// Created by Tibor Bodecs on 2022. 01. 07..
6+
//
7+
8+
import Vapor
9+
import Fluent
10+
11+
struct UserTokenAuthenticator: AsyncBearerAuthenticator {
12+
13+
func authenticate(bearer: BearerAuthorization, for req: Request) async throws {
14+
guard let token = try await UserTokenModel.query(on: req.db).filter(\.$value == bearer.token).first() else {
15+
return
16+
}
17+
18+
guard let user = try await UserAccountModel.find(token.$user.id, on: req.db) else {
19+
return
20+
}
21+
req.auth.login(AuthenticatedUser(id: user.id!, email: user.email))
22+
}
23+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// File.swift
3+
//
4+
//
5+
// Created by Tibor Bodecs on 2022. 01. 07..
6+
//
7+
8+
import Vapor
9+
10+
extension User.Token.Detail: Content {}
11+
12+
struct UserApiController {
13+
14+
func signInApi(req: Request) async throws -> User.Token.Detail {
15+
guard let user = req.auth.get(AuthenticatedUser.self) else {
16+
throw Abort(.unauthorized)
17+
}
18+
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789="
19+
let tokenValue = String((0..<64).map { _ in letters.randomElement()! })
20+
let token = UserTokenModel(value: tokenValue, userId: user.id)
21+
try await token.create(on: req.db)
22+
let userDetail = User.Account.Detail(id: user.id, email: user.email)
23+
return User.Token.Detail(id: token.id!, value: token.value, user: userDetail)
24+
}
25+
}

Chapter 13/myProject/Sources/App/Modules/User/Database/Migrations/UserMigrations.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,18 @@ enum UserMigrations {
1919
.field(UserAccountModel.FieldKeys.v1.password, .string, .required)
2020
.unique(on: UserAccountModel.FieldKeys.v1.email)
2121
.create()
22+
23+
try await db.schema(UserTokenModel.schema)
24+
.id()
25+
.field(UserTokenModel.FieldKeys.v1.value, .string, .required)
26+
.field(UserTokenModel.FieldKeys.v1.userId, .uuid, .required)
27+
.foreignKey(UserTokenModel.FieldKeys.v1.userId, references: UserAccountModel.schema, .id)
28+
.unique(on: UserTokenModel.FieldKeys.v1.value)
29+
.create()
2230
}
2331

2432
func revert(on db: Database) async throws {
33+
try await db.schema(UserTokenModel.schema).delete()
2534
try await db.schema(UserAccountModel.schema).delete()
2635
}
2736
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//
2+
// File.swift
3+
//
4+
//
5+
// Created by Tibor Bodecs on 2022. 01. 07..
6+
//
7+
8+
import Vapor
9+
import Fluent
10+
11+
final class UserTokenModel: DatabaseModelInterface {
12+
typealias Module = UserModule
13+
14+
struct FieldKeys {
15+
struct v1 {
16+
static var value: FieldKey { "value" }
17+
static var userId: FieldKey { "user_id" }
18+
}
19+
}
20+
21+
@ID() var id: UUID?
22+
@Field(key: FieldKeys.v1.value) var value: String
23+
@Parent(key: FieldKeys.v1.userId) var user: UserAccountModel
24+
25+
init() { }
26+
27+
init(id: UUID? = nil,
28+
value: String,
29+
userId: UUID)
30+
{
31+
self.id = id
32+
self.value = value
33+
self.$user.id = userId
34+
}
35+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//
2+
// File.swift
3+
//
4+
//
5+
// Created by Tibor Bodecs on 2022. 01. 07..
6+
//
7+
8+
enum User: ApiModuleInterface {
9+
10+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//
2+
// File.swift
3+
//
4+
//
5+
// Created by Tibor Bodecs on 2022. 01. 07..
6+
//
7+
8+
import Foundation
9+
10+
extension User {
11+
12+
enum Account: ApiModelInterface {
13+
typealias Module = User
14+
}
15+
}
16+
17+
extension User.Account {
18+
19+
struct List: Codable {
20+
let id: UUID
21+
let email: String
22+
}
23+
24+
struct Detail: Codable {
25+
let id: UUID
26+
let email: String
27+
}
28+
29+
struct Create: Codable {
30+
let email: String
31+
let password: String
32+
}
33+
34+
struct Update: Codable {
35+
let email: String
36+
let password: String?
37+
}
38+
39+
struct Patch: Codable {
40+
let email: String?
41+
let password: String?
42+
}
43+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// File.swift
3+
//
4+
//
5+
// Created by Tibor Bodecs on 2022. 01. 07..
6+
//
7+
8+
import Foundation
9+
10+
extension User {
11+
12+
enum Token: ApiModelInterface {
13+
typealias Module = User
14+
}
15+
}
16+
17+
extension User.Token {
18+
19+
struct Detail: Codable {
20+
let id: UUID
21+
let value: String
22+
let user: User.Account.Detail
23+
}
24+
}

Chapter 13/myProject/Sources/App/Modules/User/UserModule.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct UserModule: ModuleInterface {
1616
app.migrations.add(UserMigrations.seed())
1717

1818
app.middleware.use(UserSessionAuthenticator())
19+
app.middleware.use(UserTokenAuthenticator())
1920

2021
try router.boot(routes: app.routes)
2122
}

Chapter 13/myProject/Sources/App/Modules/User/UserRouter.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Vapor
1010
struct UserRouter: RouteCollection {
1111

1212
let frontendController = UserFrontendController()
13+
let apiController = UserApiController()
1314

1415
func boot(routes: RoutesBuilder) throws {
1516
routes.get("sign-in", use: frontendController.signInView)
@@ -18,5 +19,9 @@ struct UserRouter: RouteCollection {
1819
.post("sign-in", use: frontendController.signInAction)
1920

2021
routes.get("sign-out", use: frontendController.signOut)
22+
23+
routes.grouped("api")
24+
.grouped(UserCredentialsAuthenticator())
25+
.post("sign-in", use: apiController.signInApi)
2126
}
2227
}

0 commit comments

Comments
 (0)