Skip to content

Instantly share code, notes, and snippets.

@bubudrc
Forked from bballentine/Middleware
Created September 22, 2021 18:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bubudrc/ed070c6133ef07b7ca1f2593f73a5546 to your computer and use it in GitHub Desktop.
Save bubudrc/ed070c6133ef07b7ca1f2593f73a5546 to your computer and use it in GitHub Desktop.
Vapor - Example middleware that checks user's role before giving access to protected resources.
import Vapor
import HTTP
public class AdminAuthMiddleware: Middleware {
public let error: Error
public let authLevel: UserRole
public init(error: Error, authLevel: UserRole) {
self.error = error
self.authLevel = authLevel
}
public func respond(to request: Request, chainingTo next: Responder) throws -> Response {
guard let user = try request.auth.user() as? User else {
throw error
}
guard user.role >= authLevel.rawValue else {
throw error
}
return try next.respond(to: request)
}
}
let adminWare = AdminAuthMiddleware(error: Abort.custom(status: .badRequest, message: "You are not authorized to view this page"), authLevel: .admin)
let restController = RESTController()
drop.grouped(adminWare).resource("REST", restController)
import Vapor
import Turnstile
import TurnstileCrypto
public enum UserRole: Int {
case user = 1
case editor
case admin
}
final class User: Model {
var id: Node?
var exists: Bool = false
var name: String
var email: String
var password: String
var role: Int
var api_key_id = URandom().secureToken
var api_key_secret = URandom().secureToken
enum Error: Swift.Error {
case userNotFound
case registerNotSupported
case unsupportedCredentials
}
init(name: String, email: String, password: String) {
self.name = name
self.email = email
self.password = password
self.role = UserRole.user.rawValue
}
init(node: Node, in context: Context) throws {
self.id = nil
self.name = try node.extract("name")
self.email = try node.extract("email")
self.password = try node.extract("password")
self.role = try node.extract("role")
self.api_key_id = try node.extract("api_key_id")
self.api_key_secret = try node.extract("api_key_secret")
}
func makeNode(context: Context) throws -> Node {
return try Node(node: [
"id": id,
"name": name,
"email": email,
"role": role,
"password": password,
"api_key_id": api_key_id,
"api_key_secret": api_key_secret,
])
}
static func prepare(_ database: Database) throws {
try database.create("users") { user in
user.id()
user.string("name")
user.string("email")
user.string("password")
user.int("role")
user.string("api_key_id")
user.string("api_key_secret")
}
}
static func revert(_ database: Database) throws {
try database.delete("users")
}
}
import Auth
extension User: Auth.User {
static func register(credentials: Credentials) throws -> Auth.User {
throw Error.registerNotSupported
}
static func authenticate(credentials: Credentials) throws -> Auth.User {
var user: User?
switch credentials {
case let creds as UsernamePassword:
let result = try User.query().filter("name", creds.username).first()
if let password = result?.password, (try? BCrypt.verify(password: creds.password, matchesHash: password)) == true {
user = result
}
case let id as Identifier:
user = try User.find(id.id)
case let apiKey as APIKey:
user = try User.query().filter("email", apiKey.id).filter("api_key_secret", apiKey.secret).first()
default:
throw Error.unsupportedCredentials
}
guard let actual = user else {
throw Error.userNotFound
}
return actual
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment