如何更改 Moya 中的不记名令牌
How can I change the bearer token in Moya
文档显示了如何使目标需要不记名令牌,我就是这样做的
extension MyService: AccessTokenAuthorizable {
var authorizationType: AuthorizationType {
switch self {
case .resetPassword, .postTextBook, .bookmarkBook, .getBookmarks, .logout, .verify:
return .bearer
default:
return .none
}
}
}
然后它展示了如何向提供商添加令牌,我就是这样做的
let token = "abc123"
let authPlugin = AccessTokenPlugin(tokenClosure: token)
let provider = MoyaProvider<MyService>(plugins: [authPlugin])
但是当令牌过期时,我该如何更改令牌? Moya 是否提供了一种自动化此过程的方法,如果我收到禁止的 http 响应(意味着我未获得授权),它会自动请求令牌?
每个 API 的 authentication/authorization 的实现细节可能完全不同。这就是 Moya
不会为您处理身份验证的原因。
也就是说,实现您自己的 authentication/authorization 可以通过 多种 方式完成。这将取决于您的约束 and/or 偏好。截至今天,您可以在 Moya documentation:
中找到一些稀疏概述的解决方案
- 使用
PluginType
将您的身份验证添加到请求中。但是请认为,如果需要,这可以潜在地用于刷新令牌。您可能还需要拦截请求的完成以检测授权错误并应用您首选的恢复方案(例如刷新令牌并重试调用)。
- 同样可以使用
endpointClosure
and/or requestClosure
. 来实现
- 您还可以考虑实施
Alamofire
的 RequestAdapter
和 RequestRetrier
。根据您的需要,这可以使重试更容易。但是,在它们上您将无法直接访问您的 TargetType
,因此您可能需要找到一种方法来识别所需的不同身份验证方法(即您的 bearer
或 none
)。
对其文档的一些直接引用:
此外,我强烈鼓励任何人从 Eilodon's Networking
source code 中获得 learn/get 灵感。
对于 change/refresh 令牌,我使用了这个
static func send(request: TargetType) -> PrimitiveSequence<SingleTrait, Response> {
return provider.rx.request(request)
.retry(1)
.observeOn(ConcurrentDispatchQueueScheduler.init(qos: .default))
.filterSuccessfulStatusAndRedirectCodes()
.retryWhen({ (errorObservable: Observable<Error>) in
errorObservable.flatMap({ (error) -> Single<String> in
if let moyaError: MoyaError = error as? MoyaError, let response: Response = moyaError.response {
if **check forbidden http responses here** {
return provider.rx.request(.refreshToken(*your refresh token here*))
.filterSuccessfulStatusCodes()
.mapString(atKeyPath: "*json path to new access token*")
.catchError { (_) in
logout()
throw error
}
.flatMap({ (newAccessToken) -> PrimitiveSequence<SingleTrait, String> in
changeAccessToken()
return Single.just(newAccessToken)
})
}
}
throw error
})
})
}
static func logout() {
// logout action
}
static func changeAccessToken() {
// set new access token
}
文档显示了如何使目标需要不记名令牌,我就是这样做的
extension MyService: AccessTokenAuthorizable {
var authorizationType: AuthorizationType {
switch self {
case .resetPassword, .postTextBook, .bookmarkBook, .getBookmarks, .logout, .verify:
return .bearer
default:
return .none
}
}
}
然后它展示了如何向提供商添加令牌,我就是这样做的
let token = "abc123"
let authPlugin = AccessTokenPlugin(tokenClosure: token)
let provider = MoyaProvider<MyService>(plugins: [authPlugin])
但是当令牌过期时,我该如何更改令牌? Moya 是否提供了一种自动化此过程的方法,如果我收到禁止的 http 响应(意味着我未获得授权),它会自动请求令牌?
每个 API 的 authentication/authorization 的实现细节可能完全不同。这就是 Moya
不会为您处理身份验证的原因。
也就是说,实现您自己的 authentication/authorization 可以通过 多种 方式完成。这将取决于您的约束 and/or 偏好。截至今天,您可以在 Moya documentation:
中找到一些稀疏概述的解决方案- 使用
PluginType
将您的身份验证添加到请求中。但是请认为,如果需要,这可以潜在地用于刷新令牌。您可能还需要拦截请求的完成以检测授权错误并应用您首选的恢复方案(例如刷新令牌并重试调用)。 - 同样可以使用
endpointClosure
and/orrequestClosure
. 来实现
- 您还可以考虑实施
Alamofire
的RequestAdapter
和RequestRetrier
。根据您的需要,这可以使重试更容易。但是,在它们上您将无法直接访问您的TargetType
,因此您可能需要找到一种方法来识别所需的不同身份验证方法(即您的bearer
或none
)。
对其文档的一些直接引用:
此外,我强烈鼓励任何人从 Eilodon's Networking
source code 中获得 learn/get 灵感。
对于 change/refresh 令牌,我使用了这个
static func send(request: TargetType) -> PrimitiveSequence<SingleTrait, Response> {
return provider.rx.request(request)
.retry(1)
.observeOn(ConcurrentDispatchQueueScheduler.init(qos: .default))
.filterSuccessfulStatusAndRedirectCodes()
.retryWhen({ (errorObservable: Observable<Error>) in
errorObservable.flatMap({ (error) -> Single<String> in
if let moyaError: MoyaError = error as? MoyaError, let response: Response = moyaError.response {
if **check forbidden http responses here** {
return provider.rx.request(.refreshToken(*your refresh token here*))
.filterSuccessfulStatusCodes()
.mapString(atKeyPath: "*json path to new access token*")
.catchError { (_) in
logout()
throw error
}
.flatMap({ (newAccessToken) -> PrimitiveSequence<SingleTrait, String> in
changeAccessToken()
return Single.just(newAccessToken)
})
}
}
throw error
})
})
}
static func logout() {
// logout action
}
static func changeAccessToken() {
// set new access token
}