← 所有扩展

原生扩展

KlugAuth

com.klug.auth.KlugAuth

无需 APM。下载即用,再简单不过。

通过 ActionScript 调用 Apple 登录和 Google 登录,使用系统登录界面。您的应用会收到供服务器使用的已验证身份令牌,因此用户无需自创密码即可创建账户。

iOSAndroidmacOSMac 上的 iPad 已投入生产 €19 / 年起 · 购买

概览

大多数用户会在注册表单处放弃:用户名、必须记住的密码、落入垃圾邮件的邮箱验证码。使用 KlugAuth,他们只需点击通过 Apple 继续或通过 Google 继续即可完成。

KlugAuth 显示各平台的原生登录界面:iOS 和 macOS 上带 Face ID / Touch ID 的 Apple 登录界面,Google 在 Android 上使用的账户界面 (Credential Manager),以及 Google 在 iOS 和 macOS 上使用的系统登录窗口。它会返回服务商的身份令牌及您的 nonce,可直接在服务器上验证,另外还有在删除账户时撤销关联所需的 Apple 授权码(App Store 指南 5.1.1(v))。

不捆绑任何 Google SDK:iOS 和 macOS 上的 Google 登录在系统浏览器界面中使用带 PKCE 的标准 OAuth 流程,因此扩展保持小巧。

KlugAuth 运行在我们的应用的当前版本中,这就是我们的概念验证,用于通过 Apple 或 Google 进行注册、登录以及确认设备登出。

特性

  • 自成一体:一个 ANE,无需添加核心库或依赖 ANE
  • 在 iOS 13+、macOS 10.15+ 以及 Apple 芯片 Mac 上的 iPad 应用中使用 Apple 登录
  • 在 Android (Credential Manager) 以及 iOS / macOS(系统登录窗口,无需 Google SDK)上使用 Google 登录
  • 身份令牌、用户 ID、电子邮件和姓名;用于刷新和撤销的 Apple 授权码
  • 用于防重放保护的 nonce 辅助工具(Apple 携带其 SHA-256,Google 携带原始值)
  • 面向回访用户的 Apple 凭据状态检查(已授权 / 已撤销)
  • 成功、取消和错误事件各自独立;取消会被如实报告,绝不算作错误

支持的平台

iOS Apple + Google · arm64
Android Google · Credential Manager
macOS Apple + Google · arm64 · x86_64
Mac 上的 iPad Apple + Google

在 Android 上使用 Apple 登录可通过 Apple 的网页流程和一个小型服务器页面实现;我们可以在项目中提供该功能。isSupported(Apple)和 isGoogleSupported 会告诉您的代码设备提供哪些登录方式。

入门

将扩展添加到您的应用描述文件中:

app.xml
<extensions>
    <extensionID>com.klug.auth.KlugAuth</extensionID>
</extensions>

要使用 Apple 登录,请添加 entitlement(iOS:描述文件中的 Entitlements;macOS:签名时添加):

app.xml · Entitlements
<key>com.apple.developer.applesignin</key>
<array><string>Default</string></array>

对于 Google,请在 Google Cloud 控制台中创建 OAuth 客户端:一个 Web 客户端(其 ID 即 Android 上的令牌受众)、一个包含您的包名和 SHA-1 的 Android 客户端,以及一个供 iOS 和 macOS 使用的 iOS 客户端。

代码示例

五个完整流程,从按钮到您的服务器。每次调用都会立即返回;结果以 KlugAuthEvent 的形式到达。完整文档 →

1 · 提供设备所支持的登录方式
SignIn.as
import com.klug.auth.KlugAuth;
import com.klug.auth.KlugAuthEvent;

var auth:KlugAuth = KlugAuth.getInstance();
var nonce:String = "";   // a fresh one for every attempt

appleButton.visible  = auth.isSupported;         // iOS 13+, macOS 10.15+, iPad apps on the Mac
googleButton.visible = auth.isGoogleSupported;   // Android, iOS 13+, macOS 10.15+

auth.addEventListener( KlugAuthEvent.APPLE_SUCCESS,   onAppleSuccess );
auth.addEventListener( KlugAuthEvent.APPLE_CANCELED,  onCanceled );
auth.addEventListener( KlugAuthEvent.APPLE_ERROR,     onError );
auth.addEventListener( KlugAuthEvent.GOOGLE_SUCCESS,  onGoogleSuccess );
auth.addEventListener( KlugAuthEvent.GOOGLE_CANCELED, onCanceled );
auth.addEventListener( KlugAuthEvent.GOOGLE_ERROR,    onError );
2 · Apple 登录
Apple.as
function signInWithApple():void
{
    nonce = KlugAuth.generateNonce();          // 32 random bytes as hex, used once
    if ( !auth.signInWithApple( nonce ) )      // false: not supported, or a sheet is already open
        showMessage( "Sign in with Apple is not available." );   // your app function
}

function onAppleSuccess( e:KlugAuthEvent ):void
{
    // the token carries SHA-256 of the nonce: the server hashes the raw value and compares
    sendToServer( "apple", e.identityToken, nonce, e.fullName, e.authorizationCode );
    saveAppleUserID( e.userID );   // stable for this Apple ID; your app function
    // e.email and the names arrive only on the FIRST authorization;
    // the e-mail is always inside the identity token
}

// your app function: the server verifies the token and signs the user in
function sendToServer( provider:String, idToken:String, rawNonce:String,
                       name:String, appleCode:String = "" ):void
{
    var vars:URLVariables = new URLVariables();
    vars.provider = provider;
    vars.id_token = idToken;
    vars.nonce    = rawNonce;
    vars.name     = name;
    if ( appleCode != "" ) vars.code = appleCode;   // lets the server revoke the link later

    var req:URLRequest = new URLRequest( "https://your.server/auth" );
    req.method = URLRequestMethod.POST;
    req.data = vars;
    var loader:URLLoader = new URLLoader();
    loader.addEventListener( Event.COMPLETE, onServerAnswer );   // your app function
    loader.load( req );
}
3 · Google 登录
Google.as
import flash.system.Capabilities;

// Android: the WEB client ID, which is the token audience on your server.
// iOS and macOS: the iOS client ID, used in the system sign-in window.
var googleClientId:String = Capabilities.manufacturer.indexOf( "Android" ) >= 0
    ? "YOUR_WEB_CLIENT_ID.apps.googleusercontent.com"
    : "YOUR_IOS_CLIENT_ID.apps.googleusercontent.com";

function signInWithGoogle():void
{
    nonce = KlugAuth.generateNonce();         // Google puts the raw value into the token
    if ( !auth.signInWithGoogle( googleClientId, nonce ) )   // false: no client ID, or already open
        showMessage( "Google sign-in could not start." );
}

function onGoogleSuccess( e:KlugAuthEvent ):void
{
    // e.userID is the account e-mail; names arrive every time
    sendToServer( "google", e.identityToken, nonce, e.fullName );
}
4 · 取消与错误
Errors.as
function onCanceled( e:KlugAuthEvent ):void
{
    // the user closed the sheet: not an error, simply stay on the start screen
}

function onError( e:KlugAuthEvent ):void
{
    if ( e.type == KlugAuthEvent.GOOGLE_ERROR && e.errorCode == "NO_ACCOUNT" )
        showMessage( "Please add a Google account to this device first." );   // Android
    else
        showMessage( "Sign-in failed: " + e.errorMessage );   // e.errorCode for your log
}
5 · 检查回访的 Apple 用户
Startup.as
auth.addEventListener( KlugAuthEvent.APPLE_CREDENTIAL_STATE, function( e:KlugAuthEvent ):void {
    // e.state: authorized | revoked | notFound | transferred | unknown
    if ( e.state == "revoked" || e.state == "notFound" )
        signOut();   // your app function: the user removed the app from their Apple ID
});

var savedID:String = loadAppleUserID();   // stored after APPLE_SUCCESS; your app function
if ( auth.isSupported && savedID != "" )
    auth.getCredentialState( savedID );      // Apple only: iOS and macOS

API 概览

KlugAuth.getInstance()返回唯一实例。
isSupported在支持 Apple 登录的平台上为 True(iOS、macOS)。
isGoogleSupported在支持 Google 登录的平台上为 True(Android、iOS、macOS)。
generateNonce()静态方法。生成全新的随机 nonce(32 字节,十六进制);仅使用一次,并将相同的值发送到您的服务器。
signInWithApple(nonce)打开 Apple 登录界面。如果无法启动(不受支持,或已有登录正在进行),则返回 false。
signInWithGoogle(clientId, nonce)打开 Google 登录。Android:Web 客户端 ID;iOS / macOS:iOS 客户端 ID。如果无法启动则返回 false。
getCredentialState(userID)向 Apple 查询用户是否仍处于授权状态;答复以 APPLE_CREDENTIAL_STATE 形式到达。适用于 iOS 和 macOS。
KlugAuthEventidentityToken, authorizationCode, userID, email, givenName, familyName, fullName, state, errorCode, errorMessage.

事件

APPLE_SUCCESSidentityToken, authorizationCode, userID;email 和姓名仅在首次授权时提供。
APPLE_CANCELED用户关闭了界面。
APPLE_ERROR来自系统的 errorCode 和 errorMessage。
APPLE_CREDENTIAL_STATEuserID 和 state:authorized · revoked · notFound · transferred · unknown
GOOGLE_SUCCESSidentityToken, userID(账户的电子邮件), email, givenName, familyName.
GOOGLE_CANCELED用户关闭了界面。
GOOGLE_ERRORerrorCode 和 errorMessage;在 Android 上,当设备没有 Google 账户时为 NO_ACCOUNT。

购买 KlugAuth

一个 AIR 应用的年度许可,含 12 个月内的所有更新。付款后,您将通过电子邮件收到扩展、ActionScript 库和文档,通常在一个工作日内。许可与条款

基础版
€19 / 年
  • 一个 AIR 应用的许可
  • 12 个月内的所有更新
  • 不含支持
购买基础版
标准版
€149 / 年
  • 一个 AIR 应用的许可
  • 12 个月内的所有更新
  • 7 天内通过电子邮件答复
购买标准版
优先版
€299 / 年
  • 一个 AIR 应用的许可
  • 12 个月内的所有更新
  • 48 小时内通过电子邮件答复
购买优先版
税费在结账时由 Link (Stripe) 计算。您需要在结账时输入 AIR 应用的应用 ID。

要求

AIR SDK51.x (HARMAN)
iOSiOS 13 或更高版本
AndroidAndroid 6 或更高版本,Google Play 服务
macOSmacOS 10.15 或更高版本
Apple您的 App ID 上的 Sign in with Apple 功能
GoogleGoogle Cloud 控制台中的 OAuth 客户端