鑰匙環服務,打造無縫的跨裝置登入體驗

HMSCore發表於2023-03-30

近些年來,隨著手機技術迭代更新越來越快,使用者更換手機的週期也在縮短,在這樣的背景下,開發者不得不面臨以下問題:

同一開發者旗下常常有多個安卓應用和多形態應用(快應用和Web應用),使用者更換一個新的裝置(手機或平板)後,在新裝置上登入各應用時每次都需要重複輸入帳號和密碼,導致使用者在登入階段流失率增加,同時開發者還需要承擔額外的簡訊成本(如使用者使用簡訊登入)。

華為HMS Core鑰匙環服務(Keyring)提供憑據管理介面(Credentials Management API),為Android手機、平板提供使用者登入憑據儲存和跨應用、跨應用形態、跨裝置共享的能力。

鑰匙環服務提供了Android APIWeb API快應用API,應用程式透過呼叫這些API來使用鑰匙環服務。無論呼叫哪種形式的介面,所有的使用者憑據最終都會儲存在HMS Core的鑰匙環服務中,以便實現統一的憑據管理能力和共享能力。

一、功能特點

鑰匙環服務提供登入憑據本地儲存和跨形態、跨應用共享能力。鑰匙環服務將使用者登入憑據加密儲存在本地裝置,被儲存的憑據透過鑰匙環服務共享至同一開發者旗下的其他快應用、Web應用和安卓應用;實現跨形態、跨應用無縫登入體驗。

鑰匙環服務使用端到端加密同步技術實現登入憑據跨裝置同步能力。使用者在新老裝置上開啟“憑據多裝置同步”功能,就可以在新裝置上免密登入同一開發者旗下的各形態應用,實現跨裝置無縫登入體驗。

例如,同一開發者將旗下的兩個安卓應用和兩個快應用接入鑰匙環服務後,使用者只需要在手機A和手機B上開啟“憑據多裝置同步”功能,手機A上登入一個應用後,用手機B登入時無需再輸入帳號和密碼,實現跨裝置、跨應用、跨形態的無縫登入體驗。

二、接入優勢

打造無縫登入體驗

透過鑰匙環服務介面獲取本地儲存的使用者憑據,實現便捷登入。

保障資料安全可靠

使用者登入憑據在裝置內加密儲存,在裝置間透過端到端加密技術同步,雲端無法解密。

降低登入流失率

簡化使用者登入時操作流程,降低流失率

降低運營成本

減少使用簡訊登入,降低運營成本

三、開發步驟

開發準備

詳細準備步驟可參考華為開發者聯盟官網

整合Keyring客戶端

使用者登入場景

1、使用一個Activity例項初始化CredentialClient,可以寫在Activity的onCreate方法中。

CredentialClient credentialClient = CredentialManager.getCredentialClient(this);

2、查詢是否存在可用的憑據。

List<AppIdentity> trustedAppList = new ArrayList<>();
trustedAppList.add(new AndroidAppIdentity("yourAppName", "yourAppPackageName", "yourAppCodeSigningCertHash"));
trustedAppList.add(new WebAppIdentity("youWebSiteName", "www.yourdomain.com"));
trustedAppList.add(new WebAppIdentity("youWebSiteName", "login.yourdomain.com"));
SharedCredentialFilter sharedCredentialFilter = SharedCredentialFilter.acceptTrustedApps(trustedAppList);
credentialClient.findCredential(sharedCredentialFilter, new CredentialCallback<List<Credential>>() {
    @Override
    public void onSuccess(List<Credential> credentials) {
        if (credentials.isEmpty()) {
            Toast.makeText(MainActivity.this, R.string.no_available_credential, Toast.LENGTH_SHORT).show();
        } else {
            for (Credential credential : credentials) {
            }
        }
    }
    @Override
    public void onFailure(long errorCode, CharSequence description) {
        Toast.makeText(MainActivity.this, R.string.query_credential_failed, Toast.LENGTH_SHORT).show();
    }
});

3、呼叫Credential.getContent獲取憑據內容,在CredentialCallback<T>獲取結果。

private Credential mCredential; 
//獲取的憑據
mCredential.getContent(new CredentialCallback<byte[]>() {
    @Override
    public void onSuccess(byte[] bytes) {
        String hint = String.format(getResources().getString(R.string.get_password_ok),
                new String(bytes));
        Toast.makeText(MainActivity.this, hint, Toast.LENGTH_SHORT).show();
        mResult.setText(new String(bytes));
    }
 
    @Override
    public void onFailure(long l, CharSequence charSequence) {
        Toast.makeText(MainActivity.this, R.string.get_password_failed,
                Toast.LENGTH_SHORT).show();
        mResult.setText(R.string.get_password_failed);
    }
});

4、使用者輸入了新憑據,呼叫憑據儲存介面。

AndroidAppIdentity app2 = new AndroidAppIdentity(sharedToAppName,
                sharedToAppPackage, sharedToAppCertHash);
List<AppIdentity> sharedAppList = new ArrayList<>();
sharedAppList.add(app2);

Credential credential = new Credential(username, CredentialType.PASSWORD, userAuth,
                password.getBytes());
credential.setDisplayName("user_niceday");
credential.setSharedWith(sharedAppList);
credential.setSyncable(true);

credentialClient.saveCredential(credential, new CredentialCallback<Void>() {
    @Override
    public void onSuccess(Void unused) {
        Toast.makeText(MainActivity.this,
                R.string.save_credential_ok,
                Toast.LENGTH_SHORT).show();
    }
 
    @Override
    public void onFailure(long errorCode, CharSequence description) {
        Toast.makeText(MainActivity.this,
                R.string.save_credential_failed + " " + errorCode + ":" + description,
                Toast.LENGTH_SHORT).show();
    }
});

使用者登出場景

1、使用一個Activity例項初始化CredentialClient,可以寫在Activity的onCreate方法中。

CredentialClient credentialClient = CredentialManager.getCredentialClient(this);

2、查詢是否存在可用的憑據。

List<AppIdentity> trustedAppList = new ArrayList<>();
trustedAppList.add(new AndroidAppIdentity("yourAppName", "yourAppPackageName", "yourAppCodeSigningCertHash"));
trustedAppList.add(new WebAppIdentity("youWebSiteName", "www.yourdomain.com"));
trustedAppList.add(new WebAppIdentity("youWebSiteName", "login.yourdomain.com"));
SharedCredentialFilter sharedCredentialFilter = SharedCredentialFilter.acceptTrustedApps(trustedAppList);
credentialClient.findCredential(sharedCredentialFilter, new CredentialCallback<List<Credential>>() {
    @Override
    public void onSuccess(List<Credential> credentials) {
        if (credentials.isEmpty()) {
            Toast.makeText(MainActivity.this, R.string.no_available_credential, Toast.LENGTH_SHORT).show();
        } else {
            for (Credential credential : credentials) {
                //可以對可用憑據進行進一步處理,包括:獲取憑據相關資訊、獲取憑據內容、刪除
            }
        }
    }
 
    @Override
    public void onFailure(long errorCode, CharSequence description) {
        Toast.makeText(MainActivity.this, R.string.query_credential_failed, Toast.LENGTH_SHORT).show();
    }
});

3、呼叫deleteCredential刪除憑據,在CredentialCallback獲取結果。

credentialClient.deleteCredential(credential, new CredentialCallback<Void>() {
    @Override
    public void onSuccess(Void unused) {
        String hint = String.format(getResources().getString(R.string.delete_ok),
                credential.getUsername());
        Toast.makeText(MainActivity.this, hint, Toast.LENGTH_SHORT).show();
    }
 
    @Override
    public void onFailure(long errorCode, CharSequence description) {
        String hint = String.format(getResources().getString(R.string.delete_failed),
                description);
        Toast.makeText(MainActivity.this, hint, Toast.LENGTH_SHORT).show();
    }
});

憑據共享機制

透過API引數實現憑據共享

在呼叫saveCredential儲存憑據時,您可以透過setSharedWith設定Credential物件的屬性實現憑據共享,最多支援共享給128個應用。

示例如下:

AndroidAppIdentity app1 = new AndroidAppIdentity("your android app name",
                "your android app package name", "3C:99:C3:....");
QuickAppIdentity app2 = new QuickAppIdentity("your quick app name",
                "your quick app package name", "DC:99:C4:....");
List<AppIdentity> sharedAppList = new ArrayList<>(); // 共享關係列表
sharedAppList.add(app1);
sharedAppList.add(app2);
Credential credential = new Credential("username", CredentialType.PASSWORD, true,
                "password".getBytes());
credential.setSharedWith(sharedAppList); // 設定共享關係
credentialClient.saveCredential(credential, new CredentialCallback<Void>() {
    @Override
    public void onSuccess(Void unused) {
        Toast.makeText(MainActivity.this,
                R.string.save_credential_ok,
                Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onFailure(long errorCode, CharSequence description) {
        Toast.makeText(MainActivity.this,
                R.string.save_credential_failed + " " + errorCode + ":" + description,
                Toast.LENGTH_SHORT).show();
    }
});

透過Digital Asset Links資源實現憑據共享

您可以在Android應用的AndroidManifest.xml中新增憑據共享關係,方法如下:

1、在AndroidManifest.xml的<application>節點中新增以下內容:

<application>
           <meta-data
            android:name="asset_statements"
            android:value="@string/asset_statements" />
</application>
  1. 在res\values\strings.xml中新增以下內容:
<string name="asset_statements">your digital asset links statements</string>

Digital asset links statements是一個遵循Digital Asset links規範的JSON字串,示例如下:

[{
                   "relation": ["delegate_permission/common.get_login_creds"],
                   "target": {
                            "namespace": "web",
                            "site": "https://developer.huawei.com" // 您的網站域名
                   }
         },
         {
                   "relation": ["delegate_permission/common.get_login_creds"],
                   "target": {
                            "namespace": "android_app",
                            "package_name": "your android app package name",
                            "sha256_cert_fingerprints": [
                                     "F2:52:4D:..."
                            ]
                   }
         },
         {
                   "relation": ["delegate_permission/common.get_login_creds"],
                   "target": {
                            "namespace": "quick_app",
                            "package_name": "your quick app package name",
                            "sha256_cert_fingerprints": [
                                     "C3:68:9F:..."
                            ]
                   }
         }
]

relation屬性的值固定為["delegate_permission/common.get_login_creds"],表示把憑據共享給target屬性所描述的應用。

案例分享

航班管家和高鐵管家整合華為鑰匙環服務,為兩億使用者打造無縫登入體驗。

瞭解更多詳情>>

訪問華為開發者聯盟官網
獲取開發指導文件
華為移動服務開源倉庫地址:GitHubGitee

關注我們,第一時間瞭解 HMS Core 最新技術資訊~

相關文章