首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >蒸气4/Swift:中间件开发

蒸气4/Swift:中间件开发
EN

Stack Overflow用户
提问于 2020-05-29 04:09:51
回答 1查看 604关注 0票数 4

我对斯威夫特和瓦普尔完全陌生;

我正在尝试开发一个授权中间件,它是从我的UserModel (Fluent模型对象)调用的,并且在所需的访问级别(int)和路径(string)和

  1. 确保对用户进行身份验证,
  2. 检查UserModel.Accesslevel的实例是否为=>所需的访问级别,如果没有,则将用户重定向到'Path'.

我已经试了几天了,总是很接近,但从来没有完全得到我想要的。

我有以下内容(请原谅命名不当的对象):

代码语言:javascript
复制
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)
    }
}

我在我的用户模型中添加了以下内容

代码语言:javascript
复制
extension UserModel: Authorizable
{
    typealias ProfileAccess = UserModel
}

extension UserModel: UserAuthorizable {
    typealias AccessLevel = Int
    var accessLevel: AccessLevel { self.userprofile! }
}

以及路线本身

代码语言:javascript
复制
    // 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++帽子,而且从我所能“猜测”到的内容来看,UserModel实际上并不是用户的一个已填充的实例,即使身份验证已经完成)

我试图在使用关联类型传递帐户信息的“SessionAuthenticator”过程中合并。

我的另一个想法是检查用户是否经过身份验证,如果是的话,我可以安全地假设会话Cookie包含我的用户Id,因此我可以从DB中提取用户(再次),并从那里检查用户访问级别。

我可能会离开这里,几天后,我不知道哪条路是最好的方法,任何指导都将是非常感谢的。

干杯

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-29 07:05:40

我使用Vapor 4方法使我的User模型符合ModelAuthenticatable

代码语言:javascript
复制
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)
    }
}

在我检查用户是否存在并按照上面的方式验证密码时,它将用户登录到:

代码语言:javascript
复制
request.auth.login(user)

登录后,我使用一个自定义Middleware来检查用户是否登录和“超级用户”,如果是,那么响应将传递给链中的下一个Middleware,否则它将重定向到主/登录页面。

代码语言:javascript
复制
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中的某些路由组中使用如下:

代码语言:javascript
复制
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)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62078573

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档