我正在尝试设置一个简单的iOS示例,以便更好地了解Siesta。我的REST api需要一个访问令牌来伴随每个请求。所以(1)在应用程序的开头和(2)我随时检索HTTP 401,我需要请求一个访问令牌,然后将其放在所有未来的授权头中。
从文档中解决这个例子,我假设包含showLoginScreen
的行是我需要调用authenticationResource
来检索令牌的地方但是我如何才能立即进行失败的调用(当然不是无限循环)?谢谢。
let authURL = authenticationResource.url
configure({ url in url != authURL }, description: "catch auth failures") {
$0.config.beforeStartingRequest { _, req in // For all resources except auth:
req.onFailure { error in // If a request fails...
if error.httpStatusCode == 401 { // ...with a 401...
showLoginScreen() // ...then prompt the user to log in
}
}
}
}
答案 0 :(得分:2)
由于您提出了问题,因此文档已使用an example that answers it进行了更新。
它的关键是使用decorateRequests(…)
和Request.chained(…)
来包装所有服务的请求,以便它们在返回响应之前自动尝试刷新令牌。
以下是该示例中的代码:
authToken: String??
init() {
...
configure("**", description: "auth token") {
if let authToken = self.authToken {
$0.headers["X-Auth-Token"] = authToken // Set the token header from a var that we can update
}
$0.decorateRequests {
self.refreshTokenOnAuthFailure(request: $1)
}
}
}
// Refactor away this pyramid of doom however you see fit
func refreshTokenOnAuthFailure(request: Request) -> Request {
return request.chained {
guard case .failure(let error) = $0.response, // Did request fail…
error.httpStatusCode == 401 else { // …because of expired token?
return .useThisResponse // If not, use the response we got.
}
return .passTo(
self.createAuthToken().chained { // If so, 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.
}
}
)
}
}
func createAuthToken() -> Request {
return tokenCreationResource
.request(.post, json: userAuthData())
.onSuccess {
self.authToken = $0.jsonDict["token"] as? String // Store the new token, then…
self.invalidateConfiguration() // …make future requests use it
}
}
}