一个类型良好的 React Native 库,提供对 iOS 和 Android 上的 Apple 身份验证的支持,包括对所有AppleButton
变体的支持。
如果您不确保以下内容@invertase/react-native-apple-authentication
库将无法工作:
您使用的是 React Native 0.60
或更高版本。
(仅限 iOS)您已在计算机上设置了反应本机 iOS 开发环境(仅适用于 Mac)。如果没有,请按照 React Native 官方文档进行入门:React Native 入门文档。
(仅限 iOS)您使用的是 Xcode 版本11
或更高版本。当 Sign In with Apple 的 API 可用时,这将允许您使用 iOS 版本13
及更高版本进行开发。
一旦您确定满足上述要求,请遵循我们的初始开发环境设置指南。
版本 2 添加了 Android 支持,并对方法的访问方式进行了一些重大更改。请参阅迁移指南。
yarn add @invertase/react-native-apple-authentication
(cd ios && pod install)
您无需手动链接此模块,因为它支持 React Native 自动链接。
要在应用程序中启用“使用 Apple 登录”功能,请在项目的应用程序配置中将 ios.usesAppleSignIn 属性设置为 true:
{
"expo" : {
"ios" : {
"usesAppleSignIn" : true
}
}
}
您可能还需要运行npx expo prebuild
。
以下是帮助您启动和运行的简单步骤。 iOS 和 Android 之间的实现有所不同,因此如果您遇到问题,请务必查看文档。如果您希望看到更完整的实现,请跳过并前往下面提到的完整代码示例:
React Native Firebase
对用户进行身份验证;请参阅我们的 Firebase 指南从@invertase/react-native-apple-authentication
库导入appleAuth
(API 文档)模块和AppleButton
(API 文档)导出的成员元素。设置事件处理程序 ( onPress
) 来启动身份验证请求。
// App.js
import React from 'react' ;
import { View } from 'react-native' ;
import { AppleButton } from '@invertase/react-native-apple-authentication' ;
async function onAppleButtonPress ( ) {
}
function App ( ) {
return (
< View >
< AppleButton
buttonStyle = { AppleButton . Style . WHITE }
buttonType = { AppleButton . Type . SIGN_IN }
style = { {
width : 160 , // You must specify a width
height : 45 , // You must specify a height
} }
onPress = { ( ) => onAppleButtonPress ( ) }
/ >
< / View >
) ;
}
// App.js
import { appleAuth } from '@invertase/react-native-apple-authentication' ;
async function onAppleButtonPress ( ) {
// performs login request
const appleAuthRequestResponse = await appleAuth . performRequest ( {
requestedOperation : appleAuth . Operation . LOGIN ,
// Note: it appears putting FULL_NAME first is important, see issue #293
requestedScopes : [ appleAuth . Scope . FULL_NAME , appleAuth . Scope . EMAIL ] ,
} ) ;
// get current authentication state for user
// /! This method must be tested on a real device. On the iOS simulator it always throws an error.
const credentialState = await appleAuth . getCredentialStateForUser ( appleAuthRequestResponse . user ) ;
// use credentialState response to ensure the user is authenticated
if ( credentialState === appleAuth . State . AUTHORIZED ) {
// user is authenticated
}
}
设置用户凭据被撤销时的事件侦听器。
// App.js
import React , { useEffect } from 'react' ;
import { View } from 'react-native' ;
import { appleAuth , AppleButton } from '@invertase/react-native-apple-authentication' ;
function App ( ) {
useEffect ( ( ) => {
// onCredentialRevoked returns a function that will remove the event listener. useEffect will call this function when the component unmounts
return appleAuth . onCredentialRevoked ( async ( ) => {
console . warn ( 'If this function executes, User Credentials have been Revoked' ) ;
} ) ;
} , [ ] ) ; // passing in an empty array as the second argument ensures this is only ran once when component mounts initially.
return (
< View >
< AppleButton onPress = { ( ) => onAppleButtonPress ( ) } / >
< / View >
) ;
}
有一个操作appleAuth.Operation.LOGOUT
,但是它没有按预期工作,甚至没有被 Apple 在其示例代码中使用。请参阅此问题以获取更多信息
因此,建议在注销时清除在appleAuth.Operation.LOGIN
期间收集的所有用户数据。
确保正确配置您的 Apple 开发者帐户,以便在 Android 上进行正确的身份验证。您可以查看我们的指南以获取更多信息。
// App.js
import React from 'react' ;
import { View } from 'react-native' ;
import { appleAuthAndroid , AppleButton } from '@invertase/react-native-apple-authentication' ;
async function onAppleButtonPress ( ) {
}
// Apple authentication requires API 19+, so we check before showing the login button
function App ( ) {
return (
< View >
{ appleAuthAndroid . isSupported && (
< AppleButton
buttonStyle = { AppleButton . Style . WHITE }
buttonType = { AppleButton . Type . SIGN_IN }
onPress = { ( ) => onAppleButtonPress ( ) }
/ >
) }
< / View >
) ;
}
// App.js
import { appleAuthAndroid } from '@invertase/react-native-apple-authentication' ;
import 'react-native-get-random-values' ;
import { v4 as uuid } from 'uuid'
async function onAppleButtonPress ( ) {
// Generate secure, random values for state and nonce
const rawNonce = uuid ( ) ;
const state = uuid ( ) ;
// Configure the request
appleAuthAndroid . configure ( {
// The Service ID you registered with Apple
clientId : 'com.example.client-android' ,
// Return URL added to your Apple dev console. We intercept this redirect, but it must still match
// the URL you provided to Apple. It can be an empty route on your backend as it's never called.
redirectUri : 'https://example.com/auth/callback' ,
// The type of response requested - code, id_token, or both.
responseType : appleAuthAndroid . ResponseType . ALL ,
// The amount of user information requested from Apple.
scope : appleAuthAndroid . Scope . ALL ,
// Random nonce value that will be SHA256 hashed before sending to Apple.
nonce : rawNonce ,
// Unique state value used to prevent CSRF attacks. A UUID will be generated if nothing is provided.
state ,
} ) ;
// Open the browser window for user sign in
const response = await appleAuthAndroid . signIn ( ) ;
// Send the authorization code to your backend for verification
}
如果与react-native-macos 结合使用,该库可在MacOS 10.15+ 上运行。
yarn add react-apple-signin-auth
。 import AppleSignin from 'react-apple-signin-auth' ;
/** Apple Signin button */
const MyAppleSigninButton = ( { ... rest } ) => (
< AppleSignin
/** Auth options passed to AppleID.auth.init() */
authOptions = { {
clientId : 'SAME AS ANDROID' ,
redirectURI : 'SAME AS ANDROID' ,
scope : 'email name' ,
state : 'state' ,
/** sha256 nonce before sending to apple to unify with native firebase behavior - https://github.com/invertase/react-native-apple-authentication/issues/28 */
nonce : sha256 ( 'nonce' ) ,
/** We have to usePopup since we need clientSide authentication */
usePopup : true ,
} }
onSuccess = { ( response ) => {
console . log ( response ) ;
// {
// "authorization": {
// "state": "[STATE]",
// "code": "[CODE]",
// "id_token": "[ID_TOKEN]"
// },
// "user": {
// "email": "[EMAIL]",
// "name": {
// "firstName": "[FIRST_NAME]",
// "lastName": "[LAST_NAME]"
// }
// }
// }
} }
/ >
) ;
export default MyAppleSigninButton ;
appleAuth.performRequest
(iOS) 和appleAuthAndroid.configure
(Android) 的随机数会自动进行 SHA256 哈希处理。 crypto . createHash ( 'sha256' ) . update ( nonce ) . digest ( 'hex' ) ;
import crypto from 'crypto' ;
import appleSigninAuth from 'apple-signin-auth' ;
appleIdTokenClaims = await appleSigninAuth . verifyIdToken ( id_token , {
/** sha256 hex hash of raw nonce */
nonce : nonce ? crypto . createHash ( 'sha256' ) . update ( nonce ) . digest ( 'hex' ) : undefined ,
} ) ;
所有 API 文档均由 typedoc 生成,并可在typedocs
文件夹中找到
为什么full name
和email
返回null
?
full name
和email
,在后续登录时将返回null
,因此您需要保存这些数据。 const appleAuthRequestResponse = await appleAuth . performRequest ( {
requestedOperation : appleAuth . Operation . LOGIN ,
requestedScopes : [ appleAuth . Scope . FULL_NAME , appleAuth . Scope . EMAIL ] ,
} ) ;
Settings > Apple ID, iCloud, iTunes & App Store > Password & Security > Apps Using Your Apple ID
,点击您的应用程序,然后点击Stop Using Apple ID
。您现在可以再次登录,并且您将收到full name
和“电子邮件”。id_token
来访问email
属性服务器端。如何更改按钮语言? (iOS)
< key >CFBundleDevelopmentRegion</ key >
< string >en</ string >
< key >CFBundleAllowMixedLocalizations</ key >
< string >true</ string >
首次登录后如何获取电子邮件?
import { appleAuth } from '@invertase/react-native-apple-authentication' ;
import { jwtDecode } from 'jwt-decode' ;
const appleAuthRequestResponse = await appleAuth . performRequest ( {
requestedOperation : appleAuth . Operation . LOGIN ,
requestedScopes : [ appleAuth . Scope . EMAIL , appleAuth . Scope . FULL_NAME ]
} ) ;
// other fields are available, but full name is not
const { email , email_verified , is_private_email , sub } = jwtDecode ( appleAuthRequestResponse . identityToken )
The operation couldn’t be completed. (com.apple.AuthenticationServices.AuthorizationError error 1000.)
检查连接设置是否正确。可以在此处找到设置:初始设置
如果您在模拟器上使用getCredentialStateForUser
函数,则始终会触发此错误,因为该函数会验证设备的真实性。
您必须在真实设备上测试您的代码。
如果您使用的是模拟器,请转至管理 Apple 帐户。
搜索“设备”,选择“模拟器”,然后按“从帐户中删除”。
它应该工作正常。
"invalid_client" in Android webview
请务必阅读 Android 服务设置文档。
您传递给appleAuthAndroid.configure
的clientId
与您在 Apple 开发人员控制台中设置的服务 ID 不匹配。
您的服务 ID 附加到错误的主应用程序 ID,因此使用了错误的 Apple 密钥登录。
您传递给appleAuthAndroid.configure
redirectUri
与您在 Apple 开发者控制台中添加的返回 URL 或域/子域之一不匹配。 URL 必须完全匹配,并且不能包含查询字符串。
由转化酶构建和维护。