如何在午睡中覆盖某些资源的默认(“**”)装饰器?

Posted

技术标签:

【中文标题】如何在午睡中覆盖某些资源的默认(“**”)装饰器?【英文标题】:How to override default ("**") decorator for certain resource in siesta? 【发布时间】:2019-04-11 13:46:21 【问题描述】:

我正在尝试在服务器上将 Siesta swift 包与我的 API 一起使用。我们已经使用访问和刷新令牌设置了 JWT 身份验证。我们可以通过刷新过程成功地进行身份验证并获取新的访问令牌。但是我们提出的解决方案让我看起来有点老套。

我们正在使用这样的请求装饰器

func init() 
       service.configure("**") 
            if let session = self.appSession 
                $0.headers["Authorization"] = "Bearer \(session.tokens.access)"
            

            $0.decorateRequests 
                self.globalApiFailHandler(request: $1)
            
        

        service.configure(authRefreshResource) 
            if let session = self.appSession 
                $0.headers["Authorization-Refresh"] = "Bearer \(session.tokens.refresh)"
            

            $0.decorateRequests 
                self.refreshTokenFailure(request: $1)
            
        


private func globalApiFailHandler(request: Siesta.Request) -> Request 

        return request.chained                     //special case to Refresh Token On Auth Failure
            if case
                .failure(let error) = $0.response,  // Did request fail…
                error.httpStatusCode == 401,        // …because of expired token?
                self.appSession != nil             // we have refreshToken

                log.warning("Seems like Access Token is expired, Trying to refresh it!")
                return .passTo(
                    self.refreshAuth().chained                   // first request a new token, then:
                        if case .failure = $0.response           // If token request failed…
                            return .useThisResponse               // …report that error.
                         else 
                            return .passTo(request.repeated())    // We have a new token! Repeat the original request.
                        
                    
                )

            

            if case
                .failure(let error) = $0.response,
                error.httpStatusCode != 409 

                log.warning("Something went wrong during request: \(error)")
                self.retryLaterEvent() // TODO: Really need this here?
            

            return .useThisResponse                // If not, use the response we got.
        
    

    private func refreshTokenFailure(request: Siesta.Request) -> Request 
        return request.chained 
            if case
                .failure(let error) = $0.response   // Did request fail…

                log.error("Refresh token procedure failed with \(error).")

                if error.httpStatusCode == 409 
                    log.warning("409, Resetting app session storage! Relogin or app recreation is needed!")
                    self.relogin = true //Reset saved sessions to create new app
                    self.reloginEvent()
                 else 
                    log.warning("Something went wrong during refresh token procedure. Please retry later!")
                    self.retryLaterEvent()
                

                ///let requestError  = RequestError(userMessage: "Unable to refresh access token", cause: "")
                let response = Response.failure(error) //(requestError)
                let responseInfo = ResponseInfo(response: response)

                return .useResponse(responseInfo)                // If not, use the response we got.
            

            return .useThisResponse        // We have new token!
        
    

请注意409 返回代码检查globalApiFailHandler。它在那里是因为全局装饰器总是为authRefreshResource 调用。如果我们忽略该检查,API 将在某些服务器错误下陷入无限循环刷新令牌。

问题是如何为我们想要的特定资源禁用全局装饰器?拥有它将优雅地解决我们的问题。

【问题讨论】:

【参考方案1】:

您可以将任意谓词传递给configure(whenURLMatches:),这样您就可以外科手术般地排除您喜欢的任何东西:

service.configure(whenURLMatches:  url in url.path != "/auth" ) 
    ...

或者,如果你想排除一个你有Resource方便的URL:

service.configure(whenURLMatches:  $0 != authRefreshResource.url ) 
    ...

【讨论】:

很好,谢谢!我们很快就会试一试!

以上是关于如何在午睡中覆盖某些资源的默认(“**”)装饰器?的主要内容,如果未能解决你的问题,请参考以下文章

如何用 Jest 单元测试覆盖 TypeORM @Column 装饰器?

Android Lint:如何忽略故意仅覆盖某些默认翻译的区域语言环境字符串文件中缺少的翻译警告?

如果视图在 Django 中失败,如何创建默认错误装饰器?

烧瓶测试 - 为啥覆盖不包括导入语句和装饰器?

Python:如何在单元(鼻子)测试期间忽略装饰器?

装饰器设计:仅在方法被覆盖时执行