Notice
Recent Posts
Recent Comments
Link
Tags
- 애플
- Keychain
- 야곰아카데미
- Combine+UIKit
- 디자인패턴
- Apple
- UILabel
- iTerm
- 애플사이다
- Human Interface Guidelines
- orthogonalScrollingBehavior
- IOS
- Accessibility
- 앱개발
- CollectionView
- DiffableDataSource
- WWDC
- iPad
- HIG
- UIKit
- TOSS
- GOF
- Swift
- 전달인자 레이블
- lineBreakMode
- 스위프트
- LanguageGuide
- lineBreakStrategy
- github
- Split View
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Today
- Total
애플사이다의 iOS 개발 일지
[Keychain] 키체인 사용하기 (예제 코드) 본문
저번 포스팅 [Keychain] 공식문서 읽는 방법 - 공식문서만으로 키체인을 이해해보자 에서 Keychain 이론을 다뤘다.
이제 간단한 예제를 통해 Keychain을 사용해보자.
*이 예제에서는 비밀번호를 저장하지만, 실제로는 사용자 인증 등 토큰을 저장하는 형태로 흔히 사용한다.
1. Keychain에 비밀번호 추가 (등록)하기
먼저 Keychain에 저장할 데이터 타입을 정의하자.
이번 예제에서는 password만 저장하지만, 다른 프로퍼티를 추가/저장하는 것도 가능하다.
struct Credentials {
// var username: String // 이번에는 필요 없음
var password: String
}
Keychain 관련 Error 타입도 정의하자.
enum KeychainError: Error {
case noPassword
case unexpectedPasswordData
case unhandledError(status: OSStatus)
}
이제 Keychain 타입을 정의하고, Keychain에 비밀번호를 추가하는 메서드를 구현하자.
struct Keychain {
static func addItemsOnKeyChain(with password: String) {
let credentials = Credentials(password: password) // 저장할 비밀번호
let password = credentials.password.data(using: String.Encoding.utf8)! // pw를 암호화시킨 것
// query (질의)를 통해 개발자는 keychain에게 질문을 함
// "이걸 Keychain에 보관해줄래?"
// "kSecClassGenericPassword (일반적인 비밀번호)라는 query인데, 암호화해서 보관할 데이터는 password야"
let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
// kSecAttrAccount as String: account, // 이번에는 필요 없음
kSecValueData as String: password]
let status = SecItemAdd(query as CFDictionary, nil)
// "query를 던질건데 pw는 신경쓰지 않겠다, nil 대신 item에 담아서 서버로 보내겠다"
// 기밀정보가 많다면, data 중에서 뭘 필요로 할지 필터링할 수 있도록 한 것
if status == errSecSuccess {
print("add success")
} else if status == errSecDuplicateItem {
print("keychain에 Item이 이미 있음")
} else {
print("add failed")
}
}
}
- iOS에서는 번들마다 keychain을 부여한다. (번들은 앱이 가지고 있는 주머니)
- 위에서 정의한 addItemsOnKeyChain 메서드를 통해 keychain의 kSecClassGenericPassword에 value가 추가된다.
- 한 번 추가되면 동일한 내용을 다시 저장할 수 없다. (errSecDuplicateItem라는 OSStatus status가 발생한다.)
- 저번 포스트의 공식문서에서 봤듯이 ❗query (질의)는 Keychain에 저장할 Item이 어떤 종류의 정보인지 등을 나타낸다.
Keychain에 Item을 add 할 때는 add에 맞는 질의를 하고, search를 할 때는 search에 맞는 질의를 해야 한다. - 완성된 query는 SecItemAdd 함수의 attributes 매개변수로 전달됐다.
result 매개변수에는 nil이 전달됐다. SecItemAdd 메서드의 반환값이 필요 없다는 의미이다.
2. Keychain에 등록한 비밀번호 검색하기
static func searchItemFromKeychain() throws -> String? {
let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
// kSecMatchLimit as String: kSecMatchLimitOne,
kSecReturnAttributes as String: true, // search query에 Attribute가 있어야 원하는 값을 찾을 수 있음
kSecReturnData as String: true]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item) // &item: 키체인 참조가 아님! 복사값을 넘김
guard status != errSecItemNotFound else { throw KeychainError.noPassword }
guard status == errSecSuccess else { throw KeychainError.unhandledError(status: status) }
guard let existingItem = item as? [String : Any], // 검색해서 찾은 Item을 타입 캐스팅해서 사용하면 됨
let passwordData = existingItem[kSecValueData as String] as? Data,
let password = String(data: passwordData, encoding: String.Encoding.utf8) else {
throw KeychainError.unexpectedPasswordData
}
return password
}
- 완성된 search query를 SecItemCopyMatching 메서드의 query 매개변수에 전달했다.
result 매개변수에는 &item이 전달됐다. - 검색 결과 Keychain에 저장된 Item을 찾았다면, 변수 item에 할당된다.
- item을 타입 캐스팅하여 값에 접근할 수 있다.
3. Keychain에 등록한 비밀번호 업데이트하기
// Item을 업데이트한 뒤 결과에 따라 Alert를 띄울 예정
static func updateItemOnKeyChain(with password: String) -> UIAlertController {
let previousQuery: [String: Any] = [kSecClass as String: kSecClassGenericPassword] // search query
let newPW = password.data(using: .utf8)
let updateQuery: [String: Any] = [kSecValueData as String: newPW] // 업데이트할 Item
let status = SecItemUpdate(previousQuery as CFDictionary, updateQuery as CFDictionary)
if status == errSecSuccess {
print("update complete")
return AlertPresenter.showAlert(message: "비밀번호가 변경되었습니다")
} else {
print("not finished update")
return AlertPresenter.showAlert(message: "주의 - 비밀번호 변경 중에 오류가 발생했습니다")
}
}
- 마찬가지로 update query가 필요하다.
- SecItemUpdate 메서드를 활용한다.
- Reference
- 관련 포스트
- Apple Developer Documentation > Keychain Services
- Apple Developer Documentation > Article - Adding a Password to the Keychain
- Apple Developer Documentation > SecItemAdd(_:_:)
- Apple Developer Documentation > Article - Searching for Keychain Items
- Apple Developer Documentation > SecItemCopyMatching(::)
- Apple Developer Documentation > Article - Updating and Deleting Keychain Items
- Apple Developer Documentation > SecItemUpdate(::)
🍎 포스트가 도움이 되었다면, 공감🤍 / 구독🍹 / 공유🔗 / 댓글✏️ 로 응원해주세요. 감사합니다.
'iOS > 영문 공식문서 뜯어보기-iOS' 카테고리의 다른 글
[APNs] Push Notification 보내기 (1/2) - 관련 공식문서 요약 (0) | 2022.10.17 |
---|---|
[HIG] Notifications - title, content, actions 설정 시 고려사항 (0) | 2022.10.03 |
[Keychain] 공식문서 읽는 방법 - 공식문서만으로 키체인을 이해해보자 (긴글 주의) (0) | 2022.08.26 |
[AutoLayout] CHCR이란? Label의 default CHCR 값은? - 공식문서 오류 정정 (0) | 2022.06.16 |
[CollectionView] Diffable DataSource 이해하기 (3/3) - 상품 배너/목록/상세 화면을 구현한 예제코드 (1) | 2022.06.12 |
Comments