Vapor 4/Swift:中间件开发
Vapor 4/Swift: Middleware development
我是 Swift 和 Vapor 的新手;
我正在尝试开发一个授权中间件,该中间件从我的 UserModel(Fluent 模型对象)调用并且在所需的访问级别(int)和路径(字符串)中过去并且
- 确保用户已通过身份验证,
- 检查 UserModel.Accesslevel 的实例是否 => 所需访问权限级别,如果不是,则将用户重定向到 'Path'。
我试了几天,总是很接近,但从来没有得到我想要的东西。
我有以下(请原谅命名不当的对象):
import Vapor
public protocol Authorizable: Authenticatable {
associatedtype ProfileAccess: UserAuthorizable
}
/// status cached using `UserAuthorizable'
public protocol UserAuthorizable: Authorizable {
/// Session identifier type.
associatedtype AccessLevel: LosslessStringConvertible
/// Identifier identifier.
var accessLevel: AccessLevel { get }
}
extension Authorizable {
/// Basic middleware to redirect unauthenticated requests to the supplied path
///
/// - parameters:
/// - path: The path to redirect to if the request is not authenticated
public static func authorizeMiddleware(levelrequired: Int, path: String) -> Middleware {
return AuthorizeUserMiddleware<Self>(Self.self, levelrequired: levelrequired, path: path)
}
}
// Helper for creating authorization middleware.
///
//private final class AuthRedirectMiddleware<A>: Middleware
//where A: Authenticatable
final class AuthorizeUserMiddleware<A>: Middleware where A: Authorizable {
let levelrequired: Int
let path: String
let authLevel : Int
init(_ authorizableType: A.Type = A.self, levelrequired: Int, path: String) {
self.levelrequired = levelrequired
self.path = path
}
/// See Middleware.respond
public func respond(to req: Request, chainingTo next: Responder) -> EventLoopFuture<Response> {
if req.auth.has(A.self) {
print("--------")
print(path)
print(levelrequired)
**// print(A.ProfileAccess.AccessLevel) <- list line fails because the A.ProfileAccess.AccessLevel is a type not value**
print("--------")
}
return next.respond(to: req)
}
}
我将以下内容添加到我的用户模型
extension UserModel: Authorizable
{
typealias ProfileAccess = UserModel
}
extension UserModel: UserAuthorizable {
typealias AccessLevel = Int
var accessLevel: AccessLevel { self.userprofile! }
}
这样的路线
// setup the authentication process
let session = app.routes.grouped([
UserModelSessionAuthenticator(),
UserModelCredentialsAuthenticator(),
UserModel.authorizeMiddleware(levelrequired: 255, path: "/login"), // this will redirect the user when unauthenticted
UserModel.authRedirectMiddleware(path: "/login"), // this will redirect the user when unauthenticted
])
正确传递了路径和所需的级别,但我无法从当前用户那里获取 AccessLevel 的实例。 (我确信我已经戴上了我的 C++ 帽子,并且尽我所能 'Guess' 即使身份验证已经完成,UserModel 实际上并不是用户的填充实例)
我试图合并 'SessionAuthenticator' 使用关联类型传递帐户信息的过程。
我的另一个想法是检查用户是否经过身份验证,如果是,我可以安全地假设会话 Cookie 包含我的用户 ID,因此我可以(再次)从数据库中拉出用户并检查用户访问级别那里。
我可能会离开这里,几天后我不知道哪种方式是最好的方法,任何指导将不胜感激。
干杯
我使用 Vapor 4 方法使我的 User
模型符合 ModelAuthenticatable
:
extension User:ModelAuthenticatable
{
static let usernameKey = \User.$email
static let passwordHashKey = \User.$password
func verify(password: String) throws -> Bool
{
try Bcrypt.verify(password, created:self.password)
}
}
在我检查用户是否存在并且密码已按上述方式验证的位置,然后它让用户登录:
request.auth.login(user)
登录后,我使用自定义 Middleware
检查用户是否已登录和 'superuser',如果是,则将响应传递给下一个 Middleware
在链中,否则重定向到 home/login 页面。
struct SuperUserMiddleware:Middleware
{
func respond(to request:Request, chainingTo next:Responder) -> EventLoopFuture<Response>
{
do
{
let user = try request.auth.require(User.self)
if user.superUser { return next.respond(to:request) }
}
catch {}
let redirect = request.redirect(to:"UNPRIVILEGED")
return request.eventLoop.makeSucceededFuture(redirect)
}
}
我注册 SuperUserMiddleware
并与 configure.swift
中的某些路由组一起使用:
app.middleware.use(SessionsMiddleware(session:MemorySessions(storage:MemorySessions.Storage())))
app.middleware.use(User.sessionAuthenticator(.mysql))
let superUserMW = SuperUserMiddleware()
let userAuthSessionsMW = User.authenticator()
let events = app.grouped("/events").grouped(userAuthSessionsMW, superUserMW)
try EventRoutes(events)
我是 Swift 和 Vapor 的新手;
我正在尝试开发一个授权中间件,该中间件从我的 UserModel(Fluent 模型对象)调用并且在所需的访问级别(int)和路径(字符串)中过去并且
- 确保用户已通过身份验证,
- 检查 UserModel.Accesslevel 的实例是否 => 所需访问权限级别,如果不是,则将用户重定向到 'Path'。
我试了几天,总是很接近,但从来没有得到我想要的东西。
我有以下(请原谅命名不当的对象):
import Vapor
public protocol Authorizable: Authenticatable {
associatedtype ProfileAccess: UserAuthorizable
}
/// status cached using `UserAuthorizable'
public protocol UserAuthorizable: Authorizable {
/// Session identifier type.
associatedtype AccessLevel: LosslessStringConvertible
/// Identifier identifier.
var accessLevel: AccessLevel { get }
}
extension Authorizable {
/// Basic middleware to redirect unauthenticated requests to the supplied path
///
/// - parameters:
/// - path: The path to redirect to if the request is not authenticated
public static func authorizeMiddleware(levelrequired: Int, path: String) -> Middleware {
return AuthorizeUserMiddleware<Self>(Self.self, levelrequired: levelrequired, path: path)
}
}
// Helper for creating authorization middleware.
///
//private final class AuthRedirectMiddleware<A>: Middleware
//where A: Authenticatable
final class AuthorizeUserMiddleware<A>: Middleware where A: Authorizable {
let levelrequired: Int
let path: String
let authLevel : Int
init(_ authorizableType: A.Type = A.self, levelrequired: Int, path: String) {
self.levelrequired = levelrequired
self.path = path
}
/// See Middleware.respond
public func respond(to req: Request, chainingTo next: Responder) -> EventLoopFuture<Response> {
if req.auth.has(A.self) {
print("--------")
print(path)
print(levelrequired)
**// print(A.ProfileAccess.AccessLevel) <- list line fails because the A.ProfileAccess.AccessLevel is a type not value**
print("--------")
}
return next.respond(to: req)
}
}
我将以下内容添加到我的用户模型
extension UserModel: Authorizable
{
typealias ProfileAccess = UserModel
}
extension UserModel: UserAuthorizable {
typealias AccessLevel = Int
var accessLevel: AccessLevel { self.userprofile! }
}
这样的路线
// setup the authentication process
let session = app.routes.grouped([
UserModelSessionAuthenticator(),
UserModelCredentialsAuthenticator(),
UserModel.authorizeMiddleware(levelrequired: 255, path: "/login"), // this will redirect the user when unauthenticted
UserModel.authRedirectMiddleware(path: "/login"), // this will redirect the user when unauthenticted
])
正确传递了路径和所需的级别,但我无法从当前用户那里获取 AccessLevel 的实例。 (我确信我已经戴上了我的 C++ 帽子,并且尽我所能 'Guess' 即使身份验证已经完成,UserModel 实际上并不是用户的填充实例)
我试图合并 'SessionAuthenticator' 使用关联类型传递帐户信息的过程。
我的另一个想法是检查用户是否经过身份验证,如果是,我可以安全地假设会话 Cookie 包含我的用户 ID,因此我可以(再次)从数据库中拉出用户并检查用户访问级别那里。
我可能会离开这里,几天后我不知道哪种方式是最好的方法,任何指导将不胜感激。
干杯
我使用 Vapor 4 方法使我的 User
模型符合 ModelAuthenticatable
:
extension User:ModelAuthenticatable
{
static let usernameKey = \User.$email
static let passwordHashKey = \User.$password
func verify(password: String) throws -> Bool
{
try Bcrypt.verify(password, created:self.password)
}
}
在我检查用户是否存在并且密码已按上述方式验证的位置,然后它让用户登录:
request.auth.login(user)
登录后,我使用自定义 Middleware
检查用户是否已登录和 'superuser',如果是,则将响应传递给下一个 Middleware
在链中,否则重定向到 home/login 页面。
struct SuperUserMiddleware:Middleware
{
func respond(to request:Request, chainingTo next:Responder) -> EventLoopFuture<Response>
{
do
{
let user = try request.auth.require(User.self)
if user.superUser { return next.respond(to:request) }
}
catch {}
let redirect = request.redirect(to:"UNPRIVILEGED")
return request.eventLoop.makeSucceededFuture(redirect)
}
}
我注册 SuperUserMiddleware
并与 configure.swift
中的某些路由组一起使用:
app.middleware.use(SessionsMiddleware(session:MemorySessions(storage:MemorySessions.Storage())))
app.middleware.use(User.sessionAuthenticator(.mysql))
let superUserMW = SuperUserMiddleware()
let userAuthSessionsMW = User.authenticator()
let events = app.grouped("/events").grouped(userAuthSessionsMW, superUserMW)
try EventRoutes(events)