관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 7. 서버 - Key Chain 핸들링 본문

iOS 실전 (swift)/서버

[iOS - swift] 7. 서버 - Key Chain 핸들링

jake-kim 2020. 4. 25. 18:41

Key Chain에 대한 기본 개념은 아래 링크 참고

 

[iOS - swift] 6. 서버 - OAuth, Key Chain, 로그인 관리 토큰

1. OAuth란? - Third-party application의 인증 권환부여 및 관리를 위해서 사용 (특정 쇼핑몰 회원가입시, kakao톡아이디 또는 naver아이디로 회원가입할 수 있는 제 3자의 회원가입 정보를 이용할 수 있는 것) -..

ios-development.tistory.com

1. KeyChain

- Key Chain은 일종의 데이터 베이스

 

1) Key Chain Query

 Crate : SecItemAdd

 Read : SecItemCopyMatching

 Update : SecItemUpdate

 Delege : SecItemDelete

 

2) Key Chain Query의 데이터 타입

 - Key Chain Query는 "CFDictionary"타입이지만, 이를 상속받은 NSDictionary나 NSMutableDictionary사용

 

* 이후에는 Update는 다루지 않음 (보통 모든 데이터를 delete후 create하면 되므로)

2. 구현

* source code출처 : 꼼꼼한 재은씨의 스위프트 실전편

 

 - 재사용을 위해 TokenUtils 클래스를 생성한 후에 작성

1) CREATE

2) Read

3) Delete

4) HTTPHeaders 생성

 - API에서 Authorization header를 필요로 하는경우에는 Header를 만들어서 REQ를 해야하는데, 이 메소드를 만들어 놓으면 간편

*여기서 servieceID는 URL을 의미

 

 

* Full Source Code

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import Security
import Alamofire
 
class TokenUtils {
    
    // TokenUtils.swift
    // import Security, import Alamofire
    
    // Create
// service 파라미터는 url주소를 의미
    func create(_ service: String, account: String, value: String) {
        
        // 1. query작성
        let keyChainQuery: NSDictionary = [
            kSecClass : kSecClassGenericPassword,
            kSecAttrService: service,
            kSecAttrAccount: account,
            kSecValueData: value.data(using: .utf8, allowLossyConversion: false)!
        ]
        // allowLossyConversion은 인코딩 과정에서 손실이 되는 것을 허용할 것인지 설정
        
        // 2. Delete
        // Key Chain은 Key값에 중복이 생기면 저장할 수 없기때문에 먼저 Delete
        SecItemDelete(keyChainQuery)
        
        // 3. Create
        let status: OSStatus = SecItemAdd(keyChainQuery, nil)
        assert(status == noErr, "failed to saving Token")
    }
    
    // Read
    func read(_ service: String, account: String-> String? {
        let KeyChainQuery: NSDictionary = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrService: service,
            kSecAttrAccount: account,
            kSecReturnData: kCFBooleanTrue, // CFData타입으로 불러오라는 의미
            kSecMatchLimit: kSecMatchLimitOne // 중복되는 경우 하나의 값만 가져오라는 의미
        ]
        // CFData 타입 -> AnyObject로 받고, Data로 타입변환해서 사용하면됨
        
        // Read
        var dataTypeRef: AnyObject?
        let status = SecItemCopyMatching(KeyChainQuery, &dataTypeRef)
        
        // Read 성공 및 실패한 경우
        if(status == errSecSuccess) {
            let retrievedData = dataTypeRef as! Data
            let value = String(data: retrievedData, encoding: String.Encoding.utf8)
            return value
        } else {
            print("failed to loading, status code = \(status)")
            return nil
        }
    }
    
    // Delete
    func delete(_ service: String, account: String) {
        let keyChainQuery: NSDictionary = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrService: service,
            kSecAttrAccount: account
        ]
        
        let status = SecItemDelete(keyChainQuery)
        assert(status == noErr, "failed to delete the value, status code = \(status)")
    }
    
    // HTTPHeaders 구성
    func getAuthorizationHeader(serviceID: String-> HTTPHeaders? {
        let serviceID = serviceID
        if let accessToken = self.read(serviceID, account: "accessToken") {
            return ["Authorization" : "bearer \(accessToken)"as HTTPHeaders
        } else {
            return nil
        }
    }
}
 
 
 

(위 코드를 프레임워크로 생성 후 사용)

3. 서버와의 토큰 주고받기 (토큰 준비)

- 위에서 구현한 메소드를 이용하여 실제 서버와 토큰 주고받는 방법

* 두 토큰 모두 로그인 시 서버로 부터 받는 토큰정보

   access token : API호출 시 인증을 위한 유효시간(1시간)이 있는 토큰

   refresh token : access token만료 시 갱신을 위해 사용되는 토큰

 단, 로그아웃시 두 토큰 모두 만료 & 로그인시 기존의 access, refresh 두 토큰 만료된 후 새로운 토큰 발급

 

1) 로그인

 로그인 성공시 서버로 부터 받은 json객체에서 토큰 정보 가져와 key chain에 저장

로그인

 

2) 로그아웃

 - 클라이언트의 기본 저장소에 개인 정보 삭제

 - 클라이언트의 key chain에 인증된 인증 토큰 삭제(access token과 refresh token)

로그아웃

4. 토큰 활용

- third-party 홈, 지문인식, 얼굴인식 등에서 사용

※ 응답 캐시를 사용하지 않도록 하는 이유 : 서버와 디바이스 간에 동기화 문제를 해결하기 위함

 

 

* getAuthorizationHeader참고

* refresh token을 이용하여 access token을 받는 방법은, refresh token을 REQ하여 서버에서 access token을 수용

Comments