安全性

本指南中的功能說明可在裝置政策控制器 (DPC) 應用程式中實作的安全性管理功能。本文件包含程式碼範例,您也可以使用 Test DPC 應用程式做為 Android 企業功能的程式碼範例來源。

DPC 應用程式可在個人裝置上以設定檔擁有者模式執行,或在全代管裝置上以裝置擁有者模式執行。下表說明 DPC 以設定檔擁有者模式或裝置擁有者模式執行時可以使用的功能:

功能 商家檔案擁有者 裝置擁有者
停用應用程式存取權
封鎖來源不明的應用程式
限制 Google Play 中的帳戶
啟用企業恢復原廠設定保護機制
監控企業程序記錄和遠端錯誤報告
授予及移除用戶端憑證的存取權
安全密碼重設
工作資料夾安全性驗證問題

停用應用程式存取權

如果機構想在一天中的特定時段或一週內的某幾天,禁止員工使用 Android 裝置玩遊戲或觀看 YouTube 影片,DPC 可以暫時停用應用程式存取權。

為停用應用程式存取權,在裝置擁有者或設定檔擁有者模式下執行的 DPC 會設定 setPackagesSuspended(),讓所選應用程式視為已停用 (Google 啟動器會顯示為灰色)。使用者輕觸應用程式時,系統會顯示系統對話方塊,說明應用程式已暫停使用。

應用程式暫停後就無法啟動活動,套件的通知也會隱藏。已暫停的套件不會顯示在總覽畫面中,也無法顯示對話方塊 (包括浮動式訊息和 Snackbar),也無法播放音訊或震動裝置。

啟動器可以呼叫 isPackageSuspended() 方法,確認應用程式是否遭到停權。如要進一步瞭解如何設定應用程式停用功能,請參閱 setPackagesSuspended

封鎖來源不明的應用程式

如果不是從 Google Play (或其他信任的應用程式商店) 安裝的應用程式,稱為「來自不明來源的應用程式」。使用者安裝這些應用程式時,裝置和資料可能會面臨更多風險。

為避免有人從不明來源安裝應用程式,全代管裝置和工作資料夾的管理員元件可新增 DISALLOW_INSTALL_UNKNOWN_SOURCES 使用者限制。

工作資料夾裝置共用限制

當工作資料夾的管理員新增 DISALLOW_INSTALL_UNKNOWN_SOURCES 時,限制只會套用至工作資料夾。不過,工作資料夾管理員可為 Google Play 指定受管理設定,藉此為所有裝置套用限制。如果安裝的 Google Play 應用程式為 80812500 以上版本,就可以針對 Android 8.0 以上版本使用裝置通用限制。

如要限制應用程式安裝在 Google Play,請按照下列步驟操作:

  1. 為 Google Play 套件 com.android.vending 設定受管理的設定套件。
  2. 在套件中,請為 verify_apps:device_wide_unknown_source_block 鍵輸入布林值。
  3. 新增 ENSURE_VERIFY_APPS 使用者限制。

以下範例說明如何檢查 Google Play 是否支援這項設定,並將值設為 true

Kotlin

internal val DEVICE_WIDE_UNKNOWN_SOURCES = "verify_apps:device_wide_unknown_source_block"
internal val GOOGLE_PLAY_APK = "com.android.vending"

// ...

// Add the setting to Google Play's existing managed config. Supported in
// Google Play version 80812500 or higher--older versions ignore unsupported
// settings.
val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
var existingConfig = dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK)
val newConfig = Bundle(existingConfig)
newConfig.putBoolean(DEVICE_WIDE_UNKNOWN_SOURCES, true)
dpm.setApplicationRestrictions(adminName, GOOGLE_PLAY_APK, newConfig)

// Make sure that Google Play Protect verifies apps.
dpm.addUserRestriction(adminName, UserManager.ENSURE_VERIFY_APPS)
dpm.addUserRestriction(adminName, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)

Java

static final String DEVICE_WIDE_UNKNOWN_SOURCES =
    "verify_apps:device_wide_unknown_source_block";
static final String GOOGLE_PLAY_APK = "com.android.vending";

// ...


// Add the setting to Google Play's existing managed config. Supported in
// Google Play version 80812500 or higher--older versions ignore unsupported
// settings.
DevicePolicyManager dpm =
    (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
Bundle existingConfig =
    dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK);
Bundle newConfig = new Bundle(existingConfig);
newConfig.putBoolean(DEVICE_WIDE_UNKNOWN_SOURCES, true);
dpm.setApplicationRestrictions(adminName, GOOGLE_PLAY_APK, newConfig);

// Make sure that Google Play Protect verifies apps.
dpm.addUserRestriction(adminName, UserManager.ENSURE_VERIFY_APPS);
dpm.addUserRestriction(adminName, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);

系統設定中的使用者介面會保持運作,但系統會封鎖應用程式安裝作業。這項限制會影響日後安裝的項目 (先前安裝的應用程式仍會保留在裝置上)。裝置使用者可以繼續使用 Android Debug Bridge (ADB),在個人資料夾中安裝應用程式。

如要進一步瞭解不明來源,請參閱「其他發布選項」。

限制 Google Play 帳戶

有時機構可能想讓使用者新增個人 Google 帳戶 (例如透過 Gmail 讀取郵件),但不希望使用個人帳戶安裝應用程式。DPC 可設定使用者可在 Google Play 中使用的帳戶清單。

全代管裝置或工作資料夾的管理員元件可藉由為 Google Play 設定受管理設定來限制帳戶。如果安裝的 Google Play 應用程式為 80970100 以上版本,您就可以使用帳戶限制。

如要限制 Google Play 的帳戶,請按照下列步驟操作:

  1. 為 Google Play 套件 com.android.vending 設定受管理的設定套件。
  2. 在套件中,將以半形逗號分隔的電子郵件地址做為 allowed_accounts 鍵的字串值。

以下範例說明如何限制帳戶:

Kotlin

internal val ALLOWED_ACCOUNTS = "allowed_accounts"
internal val GOOGLE_PLAY_APK = "com.android.vending"

// ...

// Limit Google Play to one work and one personal account. Use
// a comma-separated list of account email addresses (usernames).
val googleAccounts = "ali@gmail.com,ali.connors@example.com"

// Supported in Google Play version 80970100 or higher.
val existingConfig = dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK)
val newConfig = Bundle(existingConfig)
newConfig.putString(ALLOWED_ACCOUNTS, googleAccounts)
dpm.setApplicationRestrictions(adminName, GOOGLE_PLAY_APK, newConfig)

Java

static final String ALLOWED_ACCOUNTS = "allowed_accounts";
static final String GOOGLE_PLAY_APK = "com.android.vending";

// ...


// Limit Google Play to one work and one personal account. Use
// a comma-separated list of account email addresses (usernames).
String googleAccounts = "ali@gmail.com,ali.connors@example.com";

// Supported in Google Play version 80970100 or higher.
Bundle existingConfig =
    dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK);
Bundle newConfig = new Bundle(existingConfig);
newConfig.putString(ALLOWED_ACCOUNTS, googleAccounts);
dpm.setApplicationRestrictions(adminName, GOOGLE_PLAY_APK, newConfig);

如果只想將 Google Play 設為公司帳戶,請在 DPC 知道帳戶的電子郵件地址後,將 allowed_accounts 設為單一代管帳戶。空白字串可防止使用者在 Google Play 使用任何帳戶。

啟用企業恢復原廠設定保護機制

機構可以利用企業恢復原廠設定保護機制,指定哪些 Google 帳戶可以佈建已恢復原廠設定的裝置。

消費者恢復原廠設定保護機制可防止裝置遭竊。設定精靈會要求使用者先驗證裝置個人設定檔上先前的任何 Google 帳戶,然後再允許任何人在未經授權的情況下 (例如使用 EMM) 佈建裝置。

在企業環境中,如果員工離開機構,恢復原廠設定是管理員工裝置的重要工具。但是,如果機構不知道員工的帳戶憑證,恢復原廠設定保護措施可以禁止機構將裝置提供給其他員工。

控管恢復原廠設定後的帳戶佈建作業

在裝置擁有者模式下執行時,DPC 可以使用 setFactoryResetProtectionPolicy() 控管哪些帳戶有權在恢復原廠設定後佈建裝置。如果此設定設為 null 或設為空白清單,則在恢復原廠設定後,有權佈建裝置的帳戶將是裝置個人設定檔中的帳戶。

在全代管裝置的生命週期內,DPC 可以設定這些帳戶。

  1. IT 管理員可以使用 People API 中的 people.get 方法,並具有特殊值 me。這會針對已登入的帳戶擷取 userIduserID 會在 resourceName 鍵中以 people/[userId] 格式傳回,做為整數字串。新建立的帳戶可能在 72 小時內無法恢復原廠設定。
  2. 此外,您也可以允許一或多位 IT 管理員在裝置恢復原廠設定後解鎖裝置。請這些 IT 管理員登入自己的 Google 帳戶,並按照步驟 1 與您分享 userId,以便在下一個步驟中將這些 userIds 加入清單。
  3. DPC 使用 setFactoryResetProtectionPolicy() 設定適當的應用程式限制,以設定可佈建恢復原廠設定裝置的 userId 清單。
  4. DPC 可讓帳戶在恢復原廠設定後佈建裝置,藉由傳送廣播 com.google.android.gms.auth.FRP_CONFIG_CHANGED 做為明確意圖,避免帳戶因背景限製而遭到捨棄。

Kotlin

const val ACTION_FRP_CONFIG_CHANGED =
    "com.google.android.gms.auth.FRP_CONFIG_CHANGED"
const val GMSCORE_PACKAGE = "com.google.android.gms"

// ...

// List of userId that can provision a factory reset device.
// You can use the value returned calling people/me endpoint.
val accountIds = listOf("000000000000000000000")

dpm.setFactoryResetProtectionPolicy(
    adminName,
    FactoryResetProtectionPolicy.Builder()
        .setFactoryResetProtectionAccounts(accountIds)
        .setFactoryResetProtectionEnabled(true)
        .build()
)

val frpChangedIntent = Intent(ACTION_FRP_CONFIG_CHANGED)

frpChangedIntent.setPackage(GMSCORE_PACKAGE)
context.sendBroadcast(frpChangedIntent)

Java

static final String ACTION_FRP_CONFIG_CHANGED =
    "com.google.android.gms.auth.FRP_CONFIG_CHANGED";
static final String GMSCORE_PACKAGE = "com.google.android.gms";

// ...

// List of userId that can provision a factory reset device.
// You can use the value returned calling people/me endpoint.
List<String> accountIds = new ArrayList<String>();
accountIds.add("000000000000000000000");

dpm.setFactoryResetProtectionPolicy(
    adminName,
    new FactoryResetProtectionPolicy.Builder()
        .setFactoryResetProtectionAccounts(accountIds)
        .setFactoryResetProtectionEnabled(true)
        .build());

Intent frpChangedIntent = new Intent(ACTION_FRP_CONFIG_CHANGED);

frpChangedIntent.setPackage(GMSCORE_PACKAGE);
context.sendBroadcast(frpChangedIntent);

Legacy

對於無法使用 API 級別 30 導入的 setFactoryResetProtectionPolicy() 裝置,DPC 可以使用 setApplicationRestrictions 將所選帳戶新增至 com.google.android.gms 套件的 factoryResetProtectionAdmin 受管理設定。

Kotlin

const val GOOGLE_PLAY_APK = "com.android.vending"
const val FACTORY_RESET_PROTECTION_ADMIN = "factoryResetProtectionAdmin"
const val DISABLE_FACTORY_RESET_PROTECTION_ADMIN = "disableFactoryResetProtectionAdmin"
const val GMSCORE_PACKAGE = "com.google.android.gms"

// ...

val existingConfig = dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK)
val newConfig = Bundle(existingConfig)
newConfig.putBoolean(DISABLE_FACTORY_RESET_PROTECTION_ADMIN, false)
newConfig.putString(FACTORY_RESET_PROTECTION_ADMIN, googleAccounts)
dpm.setApplicationRestrictions(adminName, GOOGLE_PLAY_APK, newConfig)

val frpChangedIntent = Intent(ACTION_FRP_CONFIG_CHANGED)

frpChangedIntent.setPackage(GMSCORE_PACKAGE)
context.sendBroadcast(frpChangedIntent)

Java

static final String GOOGLE_PLAY_APK = "com.android.vending";
static final String FACTORY_RESET_PROTECTION_ADMIN = "factoryResetProtectionAdmin";
static final String DISABLE_FACTORY_RESET_PROTECTION_ADMIN = "disableFactoryResetProtectionAdmin";
static final String GMSCORE_PACKAGE = "com.google.android.gms";

// ...

Bundle existingConfig =
        dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK);
Bundle newConfig = new Bundle(existingConfig);
newConfig.putBoolean(DISABLE_FACTORY_RESET_PROTECTION_ADMIN, false);
newConfig.putStringArray(FACTORY_RESET_PROTECTION_ADMIN,
        accountIds.toArray(new String[accountIds.size()]));
dpm.setApplicationRestrictions(adminName, GOOGLE_PLAY_APK, newConfig);

Intent frpChangedIntent = new Intent(ACTION_FRP_CONFIG_CHANGED);

frpChangedIntent.setPackage(GMSCORE_PACKAGE);
context.sendBroadcast(frpChangedIntent);

停用企業恢復原廠設定保護機制

如要停用恢復原廠設定保護措施,您的 DPC 可以使用 setFactoryResetProtectionPolicy()傳送 null 值。

Kotlin

const val ACTION_FRP_CONFIG_CHANGED =
    "com.google.android.gms.auth.FRP_CONFIG_CHANGED"
const val GMSCORE_PACKAGE = "com.google.android.gms"

// ...

dpm.setFactoryResetProtectionPolicy(adminName, null)

val frpChangedIntent = Intent(ACTION_FRP_CONFIG_CHANGED)

frpChangedIntent.setPackage(GMSCORE_PACKAGE)
context.sendBroadcast(frpChangedIntent)

Java

static final String ACTION_FRP_CONFIG_CHANGED =
    "com.google.android.gms.auth.FRP_CONFIG_CHANGED";
static final String GMSCORE_PACKAGE = "com.google.android.gms";

// ...

dpm.setFactoryResetProtectionPolicy(adminName, null);

Intent frpChangedIntent = new Intent(ACTION_FRP_CONFIG_CHANGED);

frpChangedIntent.setPackage(GMSCORE_PACKAGE);
context.sendBroadcast(frpChangedIntent);

Legacy

對於無法使用 API 級別 30 導入的 setFactoryResetProtectionPolicy() 裝置,DPC 可以使用 setApplicationRestrictions,在 com.google.android.gms 套件的 disableFactoryResetProtectionAdmin 受管理設定中,設定 true 的鍵/值。

Kotlin

const val GOOGLE_PLAY_APK = "com.android.vending"
const val FACTORY_RESET_PROTECTION_ADMIN = "factoryResetProtectionAdmin"
const val DISABLE_FACTORY_RESET_PROTECTION_ADMIN = "disableFactoryResetProtectionAdmin"
const val GMSCORE_PACKAGE = "com.google.android.gms"

// ...

val existingConfig = dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK)
val newConfig = Bundle(existingConfig)
newConfig.putBoolean(DISABLE_FACTORY_RESET_PROTECTION_ADMIN, true)

dpm.setApplicationRestrictions(
    adminName, GOOGLE_PLAY_SERVICES_PACKAGE, restrictions
)

val frpChangedIntent = Intent(ACTION_FRP_CONFIG_CHANGED)

frpChangedIntent.setPackage(GMSCORE_PACKAGE)
context.sendBroadcast(frpChangedIntent)

Java

static final String GOOGLE_PLAY_APK = "com.android.vending";
static final String FACTORY_RESET_PROTECTION_ADMIN = "factoryResetProtectionAdmin";
static final String DISABLE_FACTORY_RESET_PROTECTION_ADMIN = "disableFactoryResetProtectionAdmin";
static final String GMSCORE_PACKAGE = "com.google.android.gms";

// ...

Bundle existingConfig =
        dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK);
Bundle newConfig = new Bundle(existingConfig);
newConfig.putBoolean(DISABLE_FACTORY_RESET_PROTECTION_ADMIN, true);

dpm.setApplicationRestrictions(
    adminName, GOOGLE_PLAY_SERVICES_PACKAGE, restrictions);

Intent frpChangedIntent = new Intent(ACTION_FRP_CONFIG_CHANGED);

frpChangedIntent.setPackage(GMSCORE_PACKAGE);
context.sendBroadcast(frpChangedIntent);

監控企業處理程序記錄和遠端錯誤報告

在 EMM 控制台中,管理員可以使用企業處理程序記錄和遠端錯誤報告,監控全代管的裝置。

記錄企業裝置活動

在裝置擁有者模式下執行的 DPC 可藉由遠端追蹤裝置活動 (包括應用程式啟動、Android Debug Bridge (ADB) 活動和螢幕解鎖) 找出可疑活動。處理記錄不需要取得使用者同意。

如要啟用或停用記錄功能,DPC 會呼叫 setSecurityLoggingEnabled()

有新的批次記錄時,DeviceAdminReceiver 會收到 onSecurityLogsAvailable() 回呼。為了擷取記錄 (在收到回呼後),DPC 會呼叫 retrieveSecurityLogs()

DPC 也可以呼叫 retrievePreRebootSecurityLogs(),擷取前一個重新啟動週期中產生的安全性記錄。這是裝置上次重新啟動與前一次重新啟動之間的間隔時間。不支援 retrieveSecurityLogs() 的裝置會傳回 null。如果應用程式同時使用 retrievePreRebootSecurityLogs()retrieveSecurityLogs() 擷取記錄,請務必檢查重複的項目。
注意:這項功能只會記錄裝置上單一使用者或關聯使用者的全代管裝置上的活動。不適用於個人裝置,因為這項功能會記錄整個裝置的活動。

這項設定會記錄下列類型的動作,因此在安全性事件後稽核中非常實用:

  • 每次應用程式剛啟動時。這有助於辨識起因於遭盜用的應用程式,是否存在惡意軟體。
  • 裝置解鎖失敗。這可以識別在短時間內是否多次嘗試解鎖失敗。
  • 當使用者使用 USB 傳輸線將裝置連接到電腦時,可能會有害的 ADB 指令。

如要進一步瞭解如何閱讀記錄,請參閱 SecurityLog

開發和測試時,您可以強制系統提供任何現有的安全性記錄供 DPC 使用,不必等候整批作業。在 Android 9.0 (API 級別 28) 以上版本中,在終端機中執行下列 Android Debug Bridge (adb) 指令:

adb shell dpm force-security-logs

系統會限制工具使用頻率,並回報終端機輸出中任何意圖變慢的情形。如果有可用的記錄,DPC 會收到 onSecurityLogsAvailable() 回呼。

從遠端要求提供錯誤報告

在裝置擁有者模式下執行的 DPC 可從遠端要求回報只有一位使用者或關聯使用者的使用者裝置。錯誤報告會在收到錯誤報告的確切時間擷取裝置活動,但也可能包含過去幾小時的活動,具體取決於 Logcat 緩衝區的重新整理頻率。

如要從遠端要求錯誤報告,DPC 會呼叫 requestBugreport()

授予存取權及移除用戶端憑證的存取權

如果在設定檔擁有者或裝置擁有者模式下執行的 DPC,允許第三方應用程式管理憑證,該應用程式便可自行授予所安裝憑證的存取權,且使用者不需親自操作。如要安裝憑證供設定檔中所有應用程式存取,請使用 installKeyPair()

如需要設定的參數,請參閱 installKeyPair()。這項功能可與現有 API 搭配使用,用於管理憑證。

部署情境

如未使用 installKeyPair() 方法:

  • 使用者每次要授予憑證存取權時,都必須輕觸憑證名稱,然後輕觸「Allow」
  • 使用者會在安裝憑證時看到提示,且必須命名憑證。

使用 installKeyPair() 方法:

  • 每次使用者要授予憑證存取權時,都不需要輕觸「Allow」
  • 使用者無法重新命名憑證。
  • 管理員可進一步控管,不讓特定憑證存取的應用程式封鎖憑證。

移除用戶端憑證

授予用戶端憑證的存取權後,如要從遠端移除透過 installKeyPair() 安裝的用戶端憑證,請呼叫 removeKeyPair()

在裝置擁有者模式或設定檔擁有者模式執行的 DPC,或委派憑證安裝程式可以呼叫 removeKeyPair()。這麼做會移除安裝在指定私密金鑰別名下的憑證和私密金鑰組。

部署情境

如果機構要改用更安全的用戶端憑證,請使用此功能。如果管理員推出新憑證,且發布作業需要很長的時間,管理員可在遷移作業完成後撤銷已淘汰的憑證。

安全密碼重設

DPC 可以使用預先註冊的安全權杖授權變更,藉此重設使用者的密碼。裝置擁有者和設定檔擁有者可以呼叫安全密碼重設 API,分別變更裝置和工作資料夾的密碼。安全密碼重設功能會將 resetPassword() 替換為下列改善項目:

  • 您的 DPC 可在使用檔案型加密功能在裝置上重新啟動後,在使用者解鎖裝置或設定檔前重設密碼。
  • 密碼重設後,Android KeyStore 會保留使用者驗證的金鑰

如果您的 DPC 版本指定 Android 8.0 (API 級別 26) 以上版本,請使用安全密碼重設。呼叫 resetPassword() 時,針對指定 Android 8.0 以上版本的 DPC 會擲回 SecurityException,因此您可能需要更新 DPC。

設定並啟用權杖

DPC 必須先設定並啟用權杖,才能重設密碼。由於 DPC 可能無法直接使用權杖,因此您需要在 IT 管理員可能需要使用該權杖前設定權杖。

密碼重設權杖是加密高強度的隨機值,長度不得少於 32 位元組。為每個裝置和設定檔建立權杖,請勿重複使用或分享產生的權杖。

建議您將權杖 (或解密加密權杖) 儲存在伺服器上。如果將權杖儲存在本機憑證加密儲存空間,DPC 必須等到使用者解鎖裝置或設定檔才能重設密碼。如果將權杖儲存在本機裝置加密儲存空間且裝置遭駭,攻擊者可能會利用該權杖取得工作資料夾或主要使用者的存取權。

您可以在 DPC 中產生新權杖,也可以從伺服器擷取權杖。以下範例顯示產生權杖本身並回報給伺服器的 DPC:

Kotlin

val token = ByteArray(32)

// Generate a new token
val random = SecureRandom()
random.nextBytes(token)

// Set the token to use at a later date
val success: Boolean
success = dpm.setResetPasswordToken(DeviceAdminReceiver.getComponentName(context), token)

// Activate the token and update success variable...

// Store the token on a server
if (success) {
 sendTokenToServer(token)
}

Java

byte token[] = new byte[32]; // Minimum size token accepted

// Generate a new token
SecureRandom random = new SecureRandom();
random.nextBytes(token);

// Set the token to use at a later date
boolean success;
success = dpm.setResetPasswordToken(DeviceAdminReceiver.getComponentName(getContext()), token);

// Activate the token and update success variable ...

// Store the token on a server
if (success) {
 sendTokenToServer(token);
}

在大多數情況下,DPC 必須在設定權杖後啟用權杖。但是,如果使用者沒有螢幕鎖定密碼,系統會直接啟用權杖直接啟用。如要啟用權杖,請要求使用者確認憑證。您的 DPC 可以呼叫 KeyguardManager 方法 createConfirmDeviceCredentialIntent(),取得能開始確認的 Intent。請在使用者介面中向裝置使用者說明您要求他們進行驗證的原因。以下程式碼片段說明如何在 DPC 中啟用權杖:

Kotlin

// In your DPC, you'll need to localize the user prompt
val ACTIVATE_TOKEN_PROMPT = "Use your credentials to enable remote password reset"
val ACTIVATE_TOKEN_REQUEST = 1

// Create or fetch a token and set it in setResetPasswordToken() ...
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
val confirmIntent = keyguardManager.createConfirmDeviceCredentialIntent(null, ACTIVATE_TOKEN_PROMPT)

if (confirmIntent != null) {
 startActivityForResult(confirmIntent, ACTIVATE_TOKEN_REQUEST)
 // Check your onActivityResult() callback for RESULT_OK
} else {
 // Null means the user doesn't have a lock screen so the token is already active.
 // Call isResetPasswordTokenActive() if you need to confirm
}

Java

// In your DPC, you'll need to localize the user prompt
static final String ACTIVATE_TOKEN_PROMPT =
 "Use your credentials to enable remote password reset";
static final int ACTIVATE_TOKEN_REQUEST = 1;

// Create or fetch a token and set it in setResetPasswordToken() ...

KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
Intent confirmIntent = keyguardManager.createConfirmDeviceCredentialIntent(
  null, ACTIVATE_TOKEN_PROMPT);

if (confirmIntent != null) {
 startActivityForResult(confirmIntent, ACTIVATE_TOKEN_REQUEST);
 // Check your onActivityResult() callback for RESULT_OK
} else {
 // Null means the user doesn't have a lock screen so the token is already active.
 // Call isResetPasswordTokenActive() if you need to confirm
}

您必須先啟用 DPC 設定的權杖,才能重新啟動裝置。Android 會將未啟用的權杖儲存在記憶體中,而且重新啟動後不會保留該權杖。如果使用者在啟用權杖前重新啟動裝置,DPC 就能再次設定相同權杖或產生新權杖。

您可以呼叫 isResetPasswordTokenActive() 並檢查結果為 true,確認權杖是否已啟用。

DPC 設定並啟用權杖後,直到 DPC 刪除或取代權杖 (或裝置恢復原廠設定) 為止。權杖與密碼無關,且不會因使用者變更或清除密碼而受到影響。

刪除權杖

您可以呼叫 clearResetPasswordToken(),刪除 DPC 先前設定的權杖。您可能需要撤銷遭入侵的權杖,或是移除重設密碼的功能。以下範例說明如何透過 DPC 執行這項操作:

Kotlin

val dpm = getDpm()
val admin = DeviceAdminReceiver.getComponentName(requireActivity())

// Clear the token
if (!dpm.clearResetPasswordToken(admin)) {
 // Report the failure and possibly try later ...
}

Java

DevicePolicyManager dpm = getDpm();
ComponentName admin = DeviceAdminReceiver.getComponentName(getActivity());

// Clear the token
if (!dpm.clearResetPasswordToken(admin)) {
 // Report the failure and possibly try later ...
}

重設密碼

如果 IT 管理員需要重設密碼,請呼叫 resetPasswordWithToken(),並傳遞 DPC 設定並啟用的權杖:

Kotlin

val token: ByteArray = getTokenFromServer()
val newPassword = "password"

try {
 val result: Boolean = dpm.resetPasswordWithToken(
 DeviceAdminReceiver.getComponentName(requireContext()),
 newPassword,
 token,
 0
 )

 if (result) {
 // The password is now 'password'
 } else {
 // Using 'password' doesn't meet password restrictions
 }
} catch (e: IllegalStateException) {
 // The token doesn't match the one set earlier.
}

Java

byte token[] = getTokenFromServer();
String newPassword = "password";

try {
 boolean result = dpm.resetPasswordWithToken(
  DeviceAdminReceiver.getComponentName(getContext()), newPassword, token, 0);

 if (result) {
 // The password is now 'password'
 } else {
 // Using `password` doesn't meet password restrictions
 }
} catch (IllegalStateException e) {
 // The token doesn't match the one set earlier.
}

resetPasswordWithToken() 的呼叫會傳回 false,而密碼不會變更時,也就是新密碼不符合下列限制:

  • 字元數符合任何最低密碼長度限制。呼叫 getPasswordMinimumLength(),瞭解 IT 管理員是否已設定長度限制。
  • 密碼中的字元範圍和複雜性符合組合限制。呼叫 getPasswordQuality() 可查看 IT 管理員是否設定了組合限制。

如果密碼品質限制不需要設定密碼,您可以將 null 或空字串傳遞至 resetPasswordWithToken() 以移除密碼。

工作資料夾安全性驗證問題

在設定檔擁有者模式下執行的 DPC 可要求使用者針對在工作資料夾中執行的應用程式指定安全驗證問題。當使用者嘗試開啟任何工作應用程式時,系統會顯示安全驗證問題。如果使用者順利完成安全性驗證,系統會視需要解鎖工作資料夾並解密。

工作資料夾安全性驗證問題的運作方式

  1. 若 DPC 傳送 ACTION_SET_NEW_PASSWORD 意圖,系統會提示使用者設定安全性驗證。
  2. DPC 也可以傳送 ACTION_SET_NEW_PARENT_PROFILE_PASSWORD 意圖,提示使用者設定裝置鎖定。

DPC 可以採用與其他裝置密碼不同的政策,設定工作驗證的密碼政策。舉例來說,裝置驗證回應的最短長度可能與其他密碼所需的長度不同。DPC 會使用一般的 DevicePolicyManager 方法 (例如 setPasswordQuality()setPasswordMinimumLength()) 設定挑戰政策。

注意事項

  • DPC 可以重設工作資料夾的密碼,但無法重設裝置 (個人) 密碼。如果使用者選擇將工作和個人密碼設為相同,則工作資料夾上的 resetPassword() 只會重設工作資料夾上的密碼,而密碼不會與裝置螢幕鎖定所用的密碼相同。
  • DPC 可以使用 setOrganizationColor()setOrganizationName() 自訂工作挑戰的憑證畫面。
  • 裝置管理員無法使用 resetPassword() 清除密碼或變更已設定的密碼。裝置管理員仍可設定密碼,但前提是裝置沒有密碼、PIN 碼或解鎖圖案。

詳情請參閱 getParentProfileInstance()DevicePolicyManager 下方的說明文件。