-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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