Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- combine
- Human interface guide
- SWIFT
- uitableview
- UITextView
- 클린 코드
- MVVM
- Xcode
- 리팩토링
- map
- UICollectionView
- 스위프트
- uiscrollview
- Observable
- Clean Code
- swift documentation
- 리펙토링
- ribs
- collectionview
- 리펙터링
- swiftUI
- HIG
- RxCocoa
- clean architecture
- 애니메이션
- ios
- rxswift
- Protocol
- Refactoring
- tableView
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 3. Alamofire 사용 방법 - 토큰 갱신 (AuthenticationCredential, Authenticator, AuthenticationInterceptor) 본문
iOS 응용 (swift)
[iOS - swift] 3. Alamofire 사용 방법 - 토큰 갱신 (AuthenticationCredential, Authenticator, AuthenticationInterceptor)
jake-kim 2021. 10. 16. 15:331. Alamofire 사용 방법 - Network Layer 구현 (Moya 프레임워크처럼 사용하는 방법)
2. Alamofire 사용 방법 - 토큰 갱신 방법1 (Interceptor, adapt, retry)
3. Alamofire 사용 방법 - 토큰 갱신 (AuthenticationCredential, Authenticator, AuthenticationInterceptor)
4. Alamofire 사용 방법 - 로그 Log (EventMonitor)
AuthenticationCredential, Authenticator, AuthenticationInterceptor,
- 기존에는 RequestInterceptor를 준수하여 adapt, retry를 구현하여 사용했지만 Alamofire 5.2부터 새로 인증 전용 프로토콜이 추가되어 사용
- AuthenticationCredential와 Authenticator 프로토콜을 준수하는 구현체를 만들고 그 두 구현체를 생성자로 넣어서 사용
- AuthenticationCredential
- token값들을 가지고 있고, 만료시간 정보를 보고 refresh가 필요한지 판단하여 requiresRefresh 플래그값에 적용
import Alamofire
struct MyAuthenticationCredential: AuthenticationCredential {
let accessToken: String
let refreshToken: String
let expiredAt: Date
// 유효시간이 앞으로 5분 이하 남았다면 refresh가 필요하다고 true를 리턴 (false를 리턴하면 refresh 필요x)
var requiresRefresh: Bool { Date(timeIntervalSinceNow: 60 * 5) > expiredAt }
}
- Authenticator
- Credential타입을 가지고, 이 타입의 token을 가지고 refresh하기까지 4단계 수행
- apply()
- didRequest()
- isRequest()
- refresh()
- Authenticator - apply()
- api요청 시 AuthenticatorIndicator객체가 존재하면, 요청 전에 가로채서 apply에서 Header에 bearerToken 추가
func apply(_ credential: Credential, to urlRequest: inout URLRequest) {
urlRequest.headers.add(.authorization(bearerToken: credential.accessToken))
urlRequest.addValue(credential.refreshToken, forHTTPHeaderField: "refresh-token")
}
- Authenticator - didRequest
- api요청 후 error가 떨어진 경우, 401에러(인증에러)인 경우만 refresh가 되도록 필터링
func didRequest(_ urlRequest: URLRequest, with response: HTTPURLResponse, failDueToAuthenticationError error: Error) -> Bool {
return response.statusCode == 401
}
- Authenticator - isRequest
- 인증이 필요한 urlRequest에 대해서만 refresh가 되도록, 이 경우에만 true를 리턴하여 refresh 요청
func isRequest(_ urlRequest: URLRequest, authenticatedWith credential: Credential) -> Bool {
// bearerToken의 urlRequest대해서만 refresh를 시도 (true)
let bearerToken = HTTPHeader.authorization(bearerToken: credential.accessToken).value
return urlRequest.headers["Authorization"] == bearerToken
}
- Authenticator - refresh
- token을 refresh하는 부분
func refresh(_ credential: Credential, for session: Session, completion: @escaping (Result<Credential, Error>) -> Void) {
// TODO: refresh API 콜
/*
switch result {
case .success(let response):
completion(.success(credential))
case .failure(let error):
completion(.failure(error))
}
*/
}
사용
- 위에서 만든 AuthenticationCredential과 Authenticator를 준수한 인스턴스를 AuthenticatorInterceptor의 생성자에 넣고,
AF.request(_:interceptor)에 삽입
/// 이름과 패스워드로 로그인 + AuthencitationInterceptor 사용
static func predictWithAuth(request: PredictAgeRequest, completion: @escaping (_ succeed: Person?, _ failed: Error?) -> Void) {
// AuthenticationInterceptor 적용
let authenticator = MyAuthenticator()
let credential = MyAuthenticationCredential(accessToken: KeychainServiceImpl.shared.accessToken ?? "",
refreshToken: KeychainServiceImpl.shared.refreshToken ?? "",
expiredAt: Date(timeIntervalSinceNow: 60 * 120))
let myAuthencitationInterceptor = AuthenticationInterceptor(authenticator: authenticator,
credential: credential)
AF.request(PredictAgeTarget.predict(request), interceptor: myAuthencitationInterceptor)
.responseDecodable { (response: AFDataResponse<PredictAgeResponse>) in
switch response.result {
case .success(let response):
completion(response.toDomain, nil)
case .failure(let error):
completion(nil, error)
}
}
}
* 전체 소스코드
- https://github.com/JK0369/ExAlamofire
* 참고
'iOS 응용 (swift)' 카테고리의 다른 글
Comments