احراز هویت با استفاده از اپل در اندروید

می‌توانید با استفاده از Firebase SDK برای انجام جریان ورود به سیستم OAuth 2.0 به کاربران خود اجازه دهید با Firebase احراز هویت با استفاده از Apple ID خود انجام دهند.

قبل از اینکه شروع کنی

برای ورود به سیستم کاربرانی که از اپل استفاده می کنند، ابتدا Sign In with Apple را در سایت توسعه دهنده اپل پیکربندی کنید، سپس Apple را به عنوان ارائه دهنده ورود به سیستم برای پروژه Firebase خود فعال کنید.

به برنامه توسعه دهندگان اپل بپیوندید

ورود به سیستم با Apple فقط توسط اعضای برنامه توسعه دهنده Apple قابل پیکربندی است.

پیکربندی ورود با اپل

در سایت Apple Developer موارد زیر را انجام دهید:

  1. همانطور که در بخش اول پیکربندی ورود با اپل برای وب توضیح داده شده است، وب سایت خود را به برنامه خود مرتبط کنید. وقتی از شما خواسته شد، URL زیر را به عنوان URL بازگشتی ثبت کنید:

    https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler

    می‌توانید ID پروژه Firebase خود را در صفحه تنظیمات کنسول Firebase دریافت کنید.

    وقتی کارتان تمام شد، شناسه سرویس جدید خود را که در بخش بعدی به آن نیاز دارید، یادداشت کنید.

  2. یک ورود به سیستم با کلید خصوصی اپل ایجاد کنید. در بخش بعدی به کلید خصوصی و شناسه کلید جدید خود نیاز دارید.
  3. اگر از یکی از ویژگی‌های Firebase Authentication که برای کاربران ایمیل ارسال می‌کند، از جمله ورود به سیستم پیوند ایمیل، تأیید آدرس ایمیل، لغو تغییر حساب و موارد دیگر، استفاده می‌کنید، سرویس رله ایمیل خصوصی Apple را پیکربندی کنید و noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com را ثبت کنید (یا دامنه قالب ایمیل سفارشی شده شما) تا اپل بتواند ایمیل های ارسال شده توسط Firebase Authentication را به آدرس های ایمیل ناشناس اپل ارسال کند.

اپل را به عنوان ارائه دهنده ورود فعال کنید

  1. Firebase را به پروژه اندروید خود اضافه کنید . هنگام تنظیم برنامه خود در کنسول Firebase، حتماً امضای SHA-1 برنامه خود را ثبت کنید.
  2. در کنسول Firebase ، بخش Auth را باز کنید. در برگه روش ورود ، ارائه دهنده اپل را فعال کنید. شناسه سرویسی که در قسمت قبل ایجاد کردید را مشخص کنید. همچنین در قسمت پیکربندی جریان کد OAuth ، شناسه تیم Apple خود و شناسه کلید خصوصی و کلیدی که در قسمت قبل ایجاد کردید را مشخص کنید.

الزامات داده های ناشناس اپل را رعایت کنید

ورود به سیستم با اپل به کاربران این امکان را می دهد که هنگام ورود به سیستم، داده های خود، از جمله آدرس ایمیل خود را ناشناس نشان دهند. کاربرانی که این گزینه را انتخاب می کنند، آدرس های ایمیل با دامنه privaterelay.appleid.com . هنگامی که از ورود با اپل در برنامه خود استفاده می کنید، باید از هر گونه خط مشی یا شرایط توسعه دهنده قابل اجرا از طرف Apple در مورد این شناسه های ناشناس اپل پیروی کنید.

این شامل اخذ هرگونه رضایت کاربر مورد نیاز قبل از مرتبط کردن هر گونه اطلاعات شخصی شناسایی مستقیم با یک شناسه ناشناس اپل است. هنگام استفاده از Firebase Authentication، این ممکن است شامل اقدامات زیر باشد:

  • یک آدرس ایمیل را به یک Apple ID ناشناس پیوند دهید یا برعکس.
  • یک شماره تلفن را به یک Apple ID ناشناس پیوند دهید یا برعکس
  • یک اعتبار اجتماعی غیر ناشناس (فیس بوک، گوگل و غیره) را به یک شناسه ناشناس اپل پیوند دهید یا بالعکس.

فهرست فوق کامل نیست. به توافقنامه مجوز برنامه توسعه دهنده اپل در بخش عضویت حساب توسعه دهنده خود مراجعه کنید تا مطمئن شوید برنامه شما با الزامات اپل مطابقت دارد.

با Firebase SDK، جریان ورود به سیستم را مدیریت کنید

در Android، ساده‌ترین راه برای احراز هویت کاربران با Firebase با استفاده از حساب‌های Apple آنها، مدیریت کل جریان ورود به سیستم با Firebase Android SDK است.

برای مدیریت جریان ورود به سیستم با Firebase Android SDK، این مراحل را دنبال کنید:

  1. یک نمونه از یک OAuthProvider با استفاده از سازنده آن با شناسه ارائه دهنده apple.com :

    Java

    OAuthProvider.Builder provider = OAuthProvider.newBuilder("apple.com");
    

    Kotlin+KTX

    val provider = OAuthProvider.newBuilder("apple.com")
    
  2. اختیاری: دامنه های OAuth 2.0 اضافی را فراتر از پیش فرضی که می خواهید از ارائه دهنده احراز هویت درخواست کنید، مشخص کنید.

    Java

    List<String> scopes =
        new ArrayList<String>() {
          {
            add("email");
            add("name");
          }
        };
    provider.setScopes(scopes);
    

    Kotlin+KTX

    provider.setScopes(arrayOf("email", "name"))
    

    به‌طور پیش‌فرض، وقتی یک حساب برای هر آدرس ایمیل فعال است، Firebase دامنه ایمیل و نام را درخواست می‌کند. اگر این تنظیم را به چند حساب در هر آدرس ایمیل تغییر دهید، Firebase هیچ محدوده‌ای را از اپل درخواست نمی‌کند مگر اینکه آنها را مشخص کنید.

  3. اختیاری: اگر می خواهید صفحه ورود اپل به زبانی غیر از انگلیسی نمایش داده شود، پارامتر locale را تنظیم کنید. برای مناطق پشتیبانی شده، به اسناد ورود با اپل مراجعه کنید.

    Java

    // Localize the Apple authentication screen in French.
    provider.addCustomParameter("locale", "fr");
    

    Kotlin+KTX

    // Localize the Apple authentication screen in French.
    provider.addCustomParameter("locale", "fr")
    
  4. با استفاده از شی ارائه دهنده OAuth با Firebase احراز هویت کنید. توجه داشته باشید که برخلاف سایر عملیات FirebaseAuth ، با باز کردن یک برگه سفارشی Chrome، کنترل رابط کاربری شما را در دست می‌گیرد. در نتیجه، فعالیت خود را در OnSuccessListener و OnFailureListener که پیوست می‌کنید ارجاع ندهید، زیرا با شروع عملیات UI، فوراً جدا می‌شوند.

    ابتدا باید بررسی کنید که آیا قبلاً پاسخی دریافت کرده اید یا خیر. ورود به سیستم با این روش، Activity شما را در پس‌زمینه قرار می‌دهد، به این معنی که سیستم می‌تواند آن را در طول ورود به سیستم بازیابی کند. برای اطمینان از اینکه در صورت وقوع این اتفاق، کاربر را مجبور نمی‌کنید دوباره امتحان کند، باید بررسی کنید که آیا نتیجه از قبل وجود داشته است یا خیر.

    برای بررسی اینکه آیا یک نتیجه معلق وجود دارد، getPendingAuthResult() :

    Java

    mAuth = FirebaseAuth.getInstance();
    Task<AuthResult> pending = mAuth.getPendingAuthResult();
    if (pending != null) {
        pending.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
            @Override
            public void onSuccess(AuthResult authResult) {
                Log.d(TAG, "checkPending:onSuccess:" + authResult);
                // Get the user profile with authResult.getUser() and
                // authResult.getAdditionalUserInfo(), and the ID
                // token from Apple with authResult.getCredential().
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.w(TAG, "checkPending:onFailure", e);
            }
        });
    } else {
        Log.d(TAG, "pending: null");
    }
    

    Kotlin+KTX

    val pending = auth.pendingAuthResult
    if (pending != null) {
        pending.addOnSuccessListener { authResult ->
            Log.d(TAG, "checkPending:onSuccess:$authResult")
            // Get the user profile with authResult.getUser() and
            // authResult.getAdditionalUserInfo(), and the ID
            // token from Apple with authResult.getCredential().
        }.addOnFailureListener { e ->
            Log.w(TAG, "checkPending:onFailure", e)
        }
    } else {
        Log.d(TAG, "pending: null")
    }
    

    اگر هیچ نتیجه معلقی وجود نداشت، با فراخوانی startActivityForSignInWithProvider() شروع به ورود به سیستم کنید:

    Java

    mAuth.startActivityForSignInWithProvider(this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // Sign-in successful!
                            Log.d(TAG, "activitySignIn:onSuccess:" + authResult.getUser());
                            FirebaseUser user = authResult.getUser();
                            // ...
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            Log.w(TAG, "activitySignIn:onFailure", e);
                        }
                    });
    

    Kotlin+KTX

    auth.startActivityForSignInWithProvider(this, provider.build())
            .addOnSuccessListener { authResult ->
                // Sign-in successful!
                Log.d(TAG, "activitySignIn:onSuccess:${authResult.user}")
                val user = authResult.user
                // ...
            }
            .addOnFailureListener { e ->
                Log.w(TAG, "activitySignIn:onFailure", e)
            }
    

    برخلاف سایر ارائه دهندگان پشتیبانی شده توسط Firebase Auth، اپل URL عکس ارائه نمی دهد.

    همچنین، وقتی کاربر تصمیم می‌گیرد ایمیل خود را با برنامه به اشتراک نگذارد، اپل یک آدرس ایمیل منحصربه‌فرد برای آن کاربر ارائه می‌کند (به شکل xyz@privaterelay.appleid.com )، که آن را با برنامه شما به اشتراک می‌گذارد. اگر سرویس ارسال ایمیل خصوصی را پیکربندی کرده باشید، اپل ایمیل های ارسال شده به آدرس ناشناس را به آدرس ایمیل واقعی کاربر فوروارد می کند.

    اپل تنها اولین باری که کاربر وارد سیستم می شود، اطلاعات کاربر مانند نام نمایشی را با برنامه ها به اشتراک می گذارد. معمولاً، Firebase نام نمایشی را در اولین باری که کاربر با اپل وارد می شود، ذخیره می کند، که می توانید با getCurrentUser().getDisplayName() دریافت کنید. با این حال، اگر قبلاً از اپل برای ورود کاربر به برنامه بدون استفاده از Firebase استفاده کرده‌اید، اپل نام نمایشی کاربر را به Firebase ارائه نمی‌کند.

احراز هویت مجدد و پیوند دادن حساب

همین الگو را می‌توان با startActivityForReauthenticateWithProvider() که می‌توانید برای بازیابی اعتبار جدید برای عملیات حساسی که نیاز به ورود اخیر دارند استفاده کنید:

Java

// The user is already signed-in.
FirebaseUser firebaseUser = mAuth.getCurrentUser();

firebaseUser
    .startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
    .addOnSuccessListener(
        new OnSuccessListener<AuthResult>() {
          @Override
          public void onSuccess(AuthResult authResult) {
            // User is re-authenticated with fresh tokens and
            // should be able to perform sensitive operations
            // like account deletion and email or password
            // update.
          }
        })
    .addOnFailureListener(
        new OnFailureListener() {
          @Override
          public void onFailure(@NonNull Exception e) {
            // Handle failure.
          }
        });

Kotlin+KTX

// The user is already signed-in.
val firebaseUser = auth.getCurrentUser()

firebaseUser
    .startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
    .addOnSuccessListener( authResult -> {
        // User is re-authenticated with fresh tokens and
        // should be able to perform sensitive operations
        // like account deletion and email or password
        // update.
    })
    .addOnFailureListener( e -> {
        // Handle failure.
    })

و، می توانید از linkWithCredential() برای پیوند دادن ارائه دهندگان هویت مختلف به حساب های موجود استفاده کنید.

توجه داشته باشید که اپل از شما می‌خواهد قبل از اینکه حساب‌های اپل آن‌ها را به داده‌های دیگر مرتبط کنید، رضایت صریح را از کاربران دریافت کنید.

به عنوان مثال، برای پیوند دادن یک حساب فیس بوک به حساب فعلی Firebase، از نشانه دسترسی که از ورود کاربر به فیس بوک دریافت کرده اید استفاده کنید:

Java

// Initialize a Facebook credential with a Facebook access token.
AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());

// Assuming the current user is an Apple user linking a Facebook provider.
mAuth.getCurrentUser().linkWithCredential(credential)
    .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
      @Override
      public void onComplete(@NonNull Task<AuthResult> task) {
        if (task.isSuccessful()) {
          // Facebook credential is linked to the current Apple user.
          // The user can now sign in to the same account
          // with either Apple or Facebook.
        }
      }
    });

Kotlin+KTX

// Initialize a Facebook credential with a Facebook access token.
val credential = FacebookAuthProvider.getCredential(token.getToken())

// Assuming the current user is an Apple user linking a Facebook provider.
mAuth.getCurrentUser().linkWithCredential(credential)
    .addOnCompleteListener(this, task -> {
        if (task.isSuccessful()) {
          // Facebook credential is linked to the current Apple user.
          // The user can now sign in to the same account
          // with either Apple or Facebook.
        }
      });

پیشرفته: جریان ورود به سیستم را به صورت دستی مدیریت کنید

همچنین می‌توانید با استفاده از Firebase با استفاده از حساب Apple با مدیریت جریان ورود به سیستم با استفاده از Apple Sign-In JS SDK، ساخت دستی جریان OAuth یا با استفاده از یک کتابخانه OAuth مانند AppAuth احراز هویت کنید.

  1. برای هر درخواست ورود به سیستم، یک رشته تصادفی ایجاد کنید - یک "nonce" - که از آن استفاده می کنید تا مطمئن شوید که رمز شناسه دریافتی به طور خاص در پاسخ به درخواست احراز هویت برنامه شما اعطا شده است. این مرحله برای جلوگیری از حملات تکراری مهم است.

    می‌توانید با SecureRandom یک nonce امن رمزنگاری در Android ایجاد کنید، مانند مثال زیر:

    Java

    private String generateNonce(int length) {
        SecureRandom generator = new SecureRandom();
    
        CharsetDecoder charsetDecoder = StandardCharsets.US_ASCII.newDecoder();
        charsetDecoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
        charsetDecoder.onMalformedInput(CodingErrorAction.IGNORE);
    
        byte[] bytes = new byte[length];
        ByteBuffer inBuffer = ByteBuffer.wrap(bytes);
        CharBuffer outBuffer = CharBuffer.allocate(length);
        while (outBuffer.hasRemaining()) {
            generator.nextBytes(bytes);
            inBuffer.rewind();
            charsetDecoder.reset();
            charsetDecoder.decode(inBuffer, outBuffer, false);
        }
        outBuffer.flip();
        return outBuffer.toString();
    }
    

    Kotlin+KTX

    private fun generateNonce(length: Int): String {
        val generator = SecureRandom()
    
        val charsetDecoder = StandardCharsets.US_ASCII.newDecoder()
        charsetDecoder.onUnmappableCharacter(CodingErrorAction.IGNORE)
        charsetDecoder.onMalformedInput(CodingErrorAction.IGNORE)
    
        val bytes = ByteArray(length)
        val inBuffer = ByteBuffer.wrap(bytes)
        val outBuffer = CharBuffer.allocate(length)
        while (outBuffer.hasRemaining()) {
            generator.nextBytes(bytes)
            inBuffer.rewind()
            charsetDecoder.reset()
            charsetDecoder.decode(inBuffer, outBuffer, false)
        }
        outBuffer.flip()
        return outBuffer.toString()
    }
    

    سپس، هش SHA246 nonce را به عنوان یک رشته هگز دریافت کنید:

    Java

    private String sha256(String s) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digest = md.digest(s.getBytes());
        StringBuilder hash = new StringBuilder();
        for (byte c: digest) {
            hash.append(String.format("%02x", c));
        }
        return hash.toString();
    }
    

    Kotlin+KTX

    private fun sha256(s: String): String {
        val md = MessageDigest.getInstance("SHA-256")
        val digest = md.digest(s.toByteArray())
        val hash = StringBuilder()
        for (c in digest) {
            hash.append(String.format("%02x", c))
        }
        return hash.toString()
    }
    

    شما هش SHA256 nonce را همراه با درخواست ورود خود ارسال می‌کنید که اپل در پاسخ آن را بدون تغییر ارسال می‌کند. Firebase پاسخ را با هش کردن nonce اصلی و مقایسه آن با مقدار ارسال شده توسط Apple تأیید می کند.

  2. با استفاده از کتابخانه OAuth یا روش دیگر، جریان ورود به سیستم اپل را آغاز کنید. حتماً nonce هش شده را به عنوان پارامتر در درخواست خود لحاظ کنید.

  3. پس از دریافت پاسخ اپل، کد ID را از پاسخ دریافت کنید و از آن و nonce هش نشده برای ایجاد یک AuthCredential :

    Java

    AuthCredential credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build();
    

    Kotlin+KTX

    val credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build()
    
  4. احراز هویت با Firebase با استفاده از اعتبار Firebase:

    Java

    mAuth.signInWithCredential(credential)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
          @Override
          public void onComplete(@NonNull Task<AuthResult> task) {
            if (task.isSuccessful()) {
              // User successfully signed in with Apple ID token.
              // ...
            }
          }
        });
    

    Kotlin+KTX

    auth.signInWithCredential(credential)
          .addOnCompleteListener(this) { task ->
              if (task.isSuccessful) {
                // User successfully signed in with Apple ID token.
                // ...
              }
          }
    

اگر تماس signInWithCredential با موفقیت انجام شد، می توانید از روش getCurrentUser برای دریافت اطلاعات حساب کاربر استفاده کنید.

مراحل بعدی

پس از اینکه کاربر برای اولین بار وارد سیستم شد، یک حساب کاربری جدید ایجاد می‌شود و به اعتبارنامه‌ها (یعنی نام کاربری و رمز عبور، شماره تلفن یا اطلاعات ارائه‌دهنده تاییدیه) مرتبط می‌شود که کاربر با آن وارد شده است. این حساب جدید به‌عنوان بخشی از پروژه Firebase شما ذخیره می‌شود و می‌توان از آن برای شناسایی کاربر در همه برنامه‌های پروژه‌تان، صرف نظر از نحوه ورود کاربر به سیستم استفاده کرد.

  • در برنامه های خود، می توانید اطلاعات اولیه نمایه کاربر را از شی FirebaseUser دریافت کنید. به مدیریت کاربران مراجعه کنید.

  • در قوانین امنیتی Firebase Realtime Database و Cloud Storage، می‌توانید شناسه کاربری منحصر به فرد کاربر واردشده به سیستم را از متغیر auth دریافت کنید و از آن برای کنترل داده‌هایی که کاربر می‌تواند به آن دسترسی داشته باشد استفاده کنید.

می‌توانید به کاربران اجازه دهید با استفاده از چندین ارائه‌دهنده احراز هویت، با پیوند دادن اعتبار ارائه‌دهنده تأیید اعتبار به یک حساب کاربری موجود، به برنامه شما وارد شوند.

برای خروج از سیستم کاربر، با خروج از سیستم تماس signOut :

Java

FirebaseAuth.getInstance().signOut();

Kotlin+KTX

Firebase.auth.signOut()