feat: Begins integrating database client into vapor app.
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
import DatabaseClient
|
||||
import FluentKit
|
||||
import Foundation
|
||||
import HummingbirdBcrypt
|
||||
import SharedModels
|
||||
import Vapor
|
||||
|
||||
public extension DatabaseClient.Users {
|
||||
|
||||
static func live(database: any Database) -> Self {
|
||||
.init { create in
|
||||
.init {
|
||||
try await UserModel.query(on: database).count()
|
||||
} create: { create in
|
||||
let model = try create.toModel()
|
||||
try await model.save(on: database)
|
||||
return try model.toDTO()
|
||||
@@ -98,7 +100,7 @@ extension User.Create {
|
||||
|
||||
func toModel() throws -> UserModel {
|
||||
try validate()
|
||||
return .init(username: username, email: email, passwordHash: Bcrypt.hash(password, cost: 12))
|
||||
return try .init(username: username, email: email, passwordHash: Bcrypt.hash(password, cost: 12))
|
||||
}
|
||||
|
||||
func validate() throws {
|
||||
@@ -209,3 +211,62 @@ final class UserTokenModel: Model, Codable, @unchecked Sendable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Authentication
|
||||
|
||||
extension User: Authenticatable {}
|
||||
extension User: SessionAuthenticatable {
|
||||
public var sessionID: String { username }
|
||||
}
|
||||
|
||||
extension User: Content {}
|
||||
|
||||
public struct UserPasswordAuthenticator: AsyncBasicAuthenticator {
|
||||
public typealias User = SharedModels.User
|
||||
|
||||
public init() {}
|
||||
|
||||
public func authenticate(basic: BasicAuthorization, for request: Request) async throws {
|
||||
guard let user = try await UserModel.query(on: request.db)
|
||||
.filter(\.$username == basic.username)
|
||||
.first(),
|
||||
try Bcrypt.verify(basic.password, created: user.passwordHash)
|
||||
else {
|
||||
throw Abort(.unauthorized)
|
||||
}
|
||||
try request.auth.login(user.toDTO())
|
||||
}
|
||||
}
|
||||
|
||||
public struct UserTokenAuthenticator: AsyncBearerAuthenticator {
|
||||
public typealias User = SharedModels.User
|
||||
|
||||
public init() {}
|
||||
|
||||
public func authenticate(bearer: BearerAuthorization, for request: Request) async throws {
|
||||
guard let token = try await UserTokenModel.query(on: request.db)
|
||||
.filter(\.$value == bearer.token)
|
||||
.with(\.$user)
|
||||
.first()
|
||||
else {
|
||||
throw Abort(.unauthorized)
|
||||
}
|
||||
try request.auth.login(token.user.toDTO())
|
||||
}
|
||||
}
|
||||
|
||||
public struct UserSessionAuthenticator: AsyncSessionAuthenticator {
|
||||
public typealias User = SharedModels.User
|
||||
|
||||
public init() {}
|
||||
|
||||
public func authenticate(sessionID: User.SessionID, for request: Request) async throws {
|
||||
guard let user = try await UserModel.query(on: request.db)
|
||||
.filter(\.$username == sessionID)
|
||||
.first()
|
||||
else {
|
||||
throw Abort(.unauthorized)
|
||||
}
|
||||
try request.auth.login(user.toDTO())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user