본문 바로가기

IT/iOs

ios passkey 적용하기

 

 

 

 

 

새로운 생체인증으로 passkey라는게 등장했습니다.

나오자마자 실 프로젝트에 적용했었는데 포스팅 해놔야지 해놔야지 생각만하고 이제서야 블로그 접속을 하네요

전 직장에서 하던 프로젝트에 FIDO가 적용되어있었는데

FIDO1이 만료되고 FIDO2를 적용해야한다 하여 조사중에있던중 아이폰은 애플의 passkey 발표로 passkey를 적용하게 되었습니다.

참고 url은 하기와 같습니다.

 

 

 

 

 

 

https://developer.apple.com/documentation/authenticationservices/connecting_to_a_service_with_passkeys

 

Connecting to a service with passkeys | Apple Developer Documentation

Allow users to sign in to a service without typing a password.

developer.apple.com

https://support.apple.com/ko-kr/guide/iphone/iphf538ea8d0/ios

 

iPhone에서 패스키로 로그인하기

iPhone에서 패스키를 사용하여 암호 없이도 웹 사이트 및 앱에 안전하고 손쉽게 로그인할 수 있습니다.

support.apple.com

 

 

 

 

 

 

pass key 등록

@available(iOS 16.0, *)
    func signUpWith(response: [String: Any]?) {
        
        guard let options = response?["options"] as? [String: Any],
              let challengeoption = options["challenge"] as? String,
              let user = options["user"] as? [String: String],
              let name = user["name"],
              let userid = user["id"],
              let rp = options["rp"] as? [String: String],
              let rp_id = rp["id"] else {
            return
        }
                
        let publicKeyCredentialProvider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: rp_id)
                
        let userID = userid.decodeBase64Url()!
        let challenge = challengeoption.decodeBase64Url()!
        let registrationRequest = publicKeyCredentialProvider.createCredentialRegistrationRequest(challenge: challenge,
                                                                                                  name: name,
                                                                                                  userID: userID)
        
        
    
        if let authenticatorSelection = options["authenticatorSelection"] as? [String: String],
            let userVerification = authenticatorSelection["userVerification"] {
            registrationRequest.userVerificationPreference = ASAuthorizationPublicKeyCredentialUserVerificationPreference.init(rawValue: userVerification)
        }


        let authController = ASAuthorizationController(authorizationRequests: [ registrationRequest ] )
        authController.delegate = self
        authController.presentationContextProvider = self
        authController.performRequests()
    }

pass key 인증 

@available(iOS 16.0, *)
    func signInWith(rp_id: String,
                    challenge: String,
                    allowCredentials: [[String: Any]]?,
                    preferImmediatelyAvailableCredentials: Bool) {

        let publicKeyCredentialProvider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: rp_id)

        let challenge = challenge.decodeBase64Url()!

        let assertionRequest = publicKeyCredentialProvider.createCredentialAssertionRequest(challenge: challenge)
        
        if let credentials = allowCredentials,
            let first = credentials.first,
            let id = first["id"] as? String {
            let credentialID = id.decodeBase64Url()!
                assertionRequest.allowedCredentials = [ASAuthorizationPlatformPublicKeyCredentialDescriptor(credentialID: credentialID)]
        }

        
        let passwordCredentialProvider = ASAuthorizationPasswordProvider()
        let passwordRequest = passwordCredentialProvider.createRequest()

        let authController = ASAuthorizationController(authorizationRequests: [ assertionRequest, passwordRequest ] )
        authController.delegate = self
        authController.presentationContextProvider = self

        if preferImmediatelyAvailableCredentials {
            authController.performRequests(options: .preferImmediatelyAvailableCredentials)
        } else {
            authController.performRequests()
        }

    }

 

 

 

 

 

 

ASAuthorizationControllerDelegate 구현 

@available(iOS 16.0, *)
    func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        

		switch authorization.credential {
        case let credentialRegistration as ASAuthorizationPlatformPublicKeyCredentialRegistration:
            //A new passkey was registered
        case let credentialAssertion as ASAuthorizationPlatformPublicKeyCredentialAssertion:
            //A passkey was used to sign in
        case let passwordCredential as ASPasswordCredential:
            //A password was provided
            didFinishSignIn()
        default:
            fatalError("Received unknown authorization type.")
        }

    }
    
    func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {


        guard let authorizationError = error as? ASAuthorizationError else {
            //Unexpected authorization error
            return
        }

        if authorizationError.code == .canceled {
            //Request canceled.
        } else {
            //Error: \((error as NSError).userInfo)
        }

    }

 

적용해 본 후기는
클라이언트 개발 쪽은 거의 애플 예제에서 그대로 복붙해서 사용하면 웬만큼 된다는 것
서버가 돼야 테스트 가능해서 불편하지 막상 해보면 간단했다.
나는 암복호화 맞추는데 매우 애를 먹었었다.