本指南中的功能描述了您可以在 设备策略控制器 (DPC) 应用中实现的安全管理功能。本文档包含代码示例,您还可以使用 Test DPC 应用作为 Android 企业功能的示例代码来源。
DPC 应用可以在个人设备上的配置文件所有者模式或完全托管设备上的设备所有者模式下运行。此表指示当 DPC 在 配置文件所有者模式或设备所有者模式下运行时可用的功能。
功能 | 配置文件所有者 | 设备所有者 |
---|---|---|
禁用对应用的访问 | ✓ | ✓ |
阻止来自未知来源的应用 | ✓ | ✓ |
限制 Google Play 中的帐户 | ✓ | ✓ |
启用企业出厂重置保护 | ✓ | |
监控企业进程日志和远程错误报告 | ✓ | |
授予对客户端证书的访问权限并删除访问权限 | ✓ | ✓ |
安全密码重置 | ✓ | ✓ |
工作配置文件安全挑战 | ✓ |
禁用对应用的访问
对于希望在一天中的某些时间或一周中的某些日期阻止员工在他们的 Android 设备上玩游戏或观看 YouTube 的组织,DPC 可以暂时禁用对应用的访问。
要禁用对应用的访问,在设备所有者或配置文件所有者模式下运行的 DPC 会配置 setPackagesSuspended()
,然后所选应用的行为就像被禁用一样(Google 启动器会将应用灰显)。当用户点击应用时,他们会看到一个系统对话框,提示应用已暂停。
当应用处于暂停状态时,它无法启动活动,并且会抑制对该软件包的通知。暂停的软件包不会显示在 概览屏幕中,它们无法显示对话框(包括吐司和 Snackbars),并且它们无法播放音频或振动设备。
启动器可以通过调用 isPackageSuspended()
方法来了解应用是否已暂停。有关如何配置应用暂停的详细信息,请参阅 setPackagesSuspended
。
阻止来自未知来源的应用
未从 Google Play(或其他受信任的应用商店)安装的应用称为来自未知来源的应用。当人们安装这些应用时,设备和数据可能会面临更高的风险。
为了防止有人安装来自未知来源的应用,完全托管设备和工作配置文件的管理员组件可以添加 DISALLOW_INSTALL_UNKNOWN_SOURCES
用户限制。
工作配置文件的设备范围限制
当工作配置文件的管理员添加 DISALLOW_INSTALL_UNKNOWN_SOURCES
时,此限制仅适用于工作配置文件。但是,工作配置文件的管理员可以通过为 Google Play 设置 托管配置 来设置设备范围的限制。当安装的 Google Play 应用版本为 80812500 或更高版本时,Android 8.0(或更高版本)中提供设备范围的限制。
要将应用安装限制在 Google Play 中,请按照以下步骤操作
- 为 Google Play 包
com.android.vending
设置托管配置包。 - 在包中,为
verify_apps:device_wide_unknown_source_block
密钥设置布尔值。 - 添加
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 调试桥 (adb) 继续将应用安装到个人资料中。
要了解有关未知来源的更多信息,请阅读 替代分发选项。
限制 Google Play 中的帐户
有时,组织可能希望允许用户添加个人 Google 帐户(例如,在 Gmail 中读取邮件),但又不想让个人帐户安装应用。您的 DPC 可以设置用户可以在 Google Play 中使用的帐户列表。
完全托管设备或工作配置文件的管理员组件可以通过为 Google Play 设置 托管配置 来限制帐户。当安装的 Google Play 应用版本为 80970100 或更高版本时,提供帐户限制功能。
要限制 Google Play 中的帐户,请执行以下操作
- 为 Google Play 包
com.android.vending
设置托管配置包。 - 在包中,将逗号分隔的电子邮件地址作为字符串值放入
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 = "[email protected],[email protected]" // 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 = "[email protected],[email protected]"; // 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 帐户可以预配已出厂重置的设备。
消费者出厂重置保护旨在防止设备被盗。在允许任何人预配未经授权的出厂重置后的设备(例如使用 EMM)之前,设置向导要求用户对设备个人资料中以前存在的任何 Google 帐户进行身份验证。
在企业环境中,出厂重置是管理员工设备的重要工具,尤其是在员工离开组织时。但是,如果组织不知道员工的帐户凭据,出厂重置保护可能会阻止组织将设备分配给其他员工。
控制出厂重置后的预配
在设备拥有者模式下运行时,您的 DPC 可以使用 setFactoryResetProtectionPolicy()
控制哪些帐户被授权在出厂重置后预配设备。如果此配置设置为 null
或设置为空列表,则在出厂重置后被授权预配设备的帐户是设备个人资料中的帐户。
DPC 可以在完全托管设备的整个生命周期内配置这些帐户。
- IT 管理员可以使用人员 API 的
people.get
方法 使用特殊值me
。这将检索登录帐户的userId
。userID
以people/[userId]
的形式作为整数字符串返回,位于resourceName
密钥中。新创建的帐户可能需要 72 小时才能用于出厂重置。 - 您可能还想启用一个或多个 IT 管理员以在出厂重置后解锁设备。让这些 IT 管理员中的每一个都登录到他们的 Google 帐户,并按照步骤 1 操作并与您共享他们的
userId
,以便您可以将这些userIds
添加到下一步中的列表中。 - DPC 使用
setFactoryResetProtectionPolicy()
设置适当的应用限制,以设置可以预配出厂重置设备的userId
列表。 - 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);
旧版
对于无法使用 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);
旧版
对于无法使用 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 调试桥 (adb) 活动和屏幕解锁)来识别可疑活动。流程日志不需要用户同意。
要启用或禁用日志记录,DPC 会调用 setSecurityLoggingEnabled()
。
当有新的日志批次可用时, DeviceAdminReceiver
会接收 onSecurityLogsAvailable()
回调。要检索日志(在收到回调后),DPC 会调用 retrieveSecurityLogs()
。
DPC 还可以调用 retrievePreRebootSecurityLogs()
以获取在上一次重启周期中生成的安全性日志。这是上次设备重启与其之前的重启之间的时间间隔。不支持 retrieveSecurityLogs()
的设备将返回 null
。如果您的应用使用 retrievePreRebootSecurityLogs()
和 retrieveSecurityLogs()
检索日志,则需要检查重复项。
注意:此功能仅记录在具有单个用户或设备上的 关联用户 的完全托管设备上的活动。此功能不适用于个人设备,因为它会记录设备范围的活动。
此设置在安全事件后审计中很有用,因为它会记录以下类型的操作
- 每次应用新启动时。这有助于识别是否存在以受损应用启动的恶意软件。
- 设备上不成功的解锁尝试。这有助于识别短时间内是否存在多次失败的解锁尝试。
- 当用户使用 USB 线缆将设备连接到计算机时,潜在有害的 adb 命令。
有关如何读取日志的详细信息,请参阅 SecurityLog
。
在开发和测试期间,您可以强制系统使任何现有的安全日志可供您的 DPC 使用——您无需等待完整的批次。在 Android 9.0(API 级别 28)或更高版本中,在您的终端中运行以下 Android 调试桥 (adb) 命令
adb shell dpm force-security-logs
系统会限制您使用此工具的频率,并在终端输出中报告任何故意减慢的操作。如果有日志可用,您的 DPC 会接收 onSecurityLogsAvailable()
回调。
远程请求错误报告
在设备拥有者模式下运行的 DPC 可以远程请求仅具有一个用户或 关联用户 的用户设备的错误报告。错误报告会捕获请求错误报告时的确切设备活动,但也可能包含前几个小时的活动,具体取决于 logcat 缓冲区刷新的频率。
要远程请求错误报告,DPC 会调用 requestBugreport()
- 如果用户接受共享错误报告,则 DPC 会使用
onBugreportShared()
接收错误报告。 - 如果用户拒绝共享错误报告,则 DPC 会使用
onBugreportSharingDeclined()
接收共享请求被拒绝的消息。 - 如果错误报告失败,则 DPC 会看到
onBugreportFailed()
,并显示BUGREPORT_FAILURE_FAILED_COMPLETING
或BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE
。
授予对客户端证书的访问权限并删除访问权限
如果在配置文件所有者或设备拥有者模式下运行的 DPC 授予第三方应用管理证书的功能,则该应用可以在没有用户干预的情况下授予自身对安装的证书的访问权限。要安装配置文件中所有应用都可以访问的证书,请使用 installKeyPair()
。
有关要配置的参数,请参阅installKeyPair()
。此功能与用于管理证书的现有 API 协同工作。
部署场景
没有 installKeyPair()
方法
- 每次用户想要授予证书访问权限时,都需要点击证书名称并点击**允许**。
- 安装证书时,用户会看到一个提示,并必须为证书命名。
使用 installKeyPair()
方法
- 用户无需每次想要授予证书访问权限时都点击**允许**。
- 用户无法重命名证书。
- 管理员拥有更多控制权,因为他们可以阻止不应该访问特定证书的应用使用证书。
删除客户端证书
在授予客户端证书访问权限后,要远程删除通过installKeyPair()
安装的客户端证书,请调用removeKeyPair()
。
以设备拥有者模式或配置文件拥有者模式运行的 DPC 或委托的证书安装程序可以调用removeKeyPair()
。这将删除在给定私钥别名下安装的证书和私钥对。
部署场景
如果组织正在迁移到更安全的客户端证书形式,请使用此功能。如果管理员推出新证书,并且其分发需要大量时间,则管理员可以在迁移完成后撤销已弃用的证书。
安全密码重置
您的 DPC 可以通过使用预注册的安全令牌授权更改来重置用户的密码。设备拥有者和配置文件拥有者可以分别调用安全密码重置 API 来更改设备和工作配置文件的密码。安全密码重置使用以下改进替换了resetPassword()
如果您的 DPC 构建目标为 Android 8.0(API 级别 26)或更高版本,则应使用安全密码重置。在面向 Android 8.0 或更高版本的 DPC 中调用resetPassword()
会抛出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
,该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 可以再次设置相同的令牌或生成新的令牌。
您的 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 可以要求用户为在工作配置文件中运行的应用指定安全挑战。当用户尝试打开任何工作应用时,系统会显示安全挑战。如果用户成功完成安全挑战,系统将解锁工作配置文件并在必要时对其进行解密。
工作配置文件安全挑战的工作原理
- 如果 DPC 发送
ACTION_SET_NEW_PASSWORD
意图,系统会提示用户设置安全挑战。 - DPC 还可以发送
ACTION_SET_NEW_PARENT_PROFILE_PASSWORD
意图以提示用户设置设备锁。
DPC 可以为工作挑战设置与其他设备密码不同的密码策略。例如,设备挑战响应的最小长度可以与其他密码所需的长度不同。DPC 使用常用的DevicePolicyManager
方法(例如setPasswordQuality()
和setPasswordMinimumLength()
)来设置挑战策略。
注意事项
- DPC 可以重置工作配置文件上的密码,但不能重置设备(个人)密码。如果用户选择将工作密码和个人密码设置为相同,则在工作配置文件上
resetPassword()
会导致仅重置工作配置文件上的密码,并且密码将与设备锁屏密码不同。 - DPC 可以使用
setOrganizationColor()
和setOrganizationName()
自定义工作挑战的凭据屏幕。 - 设备管理员无法使用
resetPassword()
清除密码或更改已设置的密码。设备管理员仍然可以设置密码,但仅当设备没有密码、PIN 或图案时。
有关其他信息,请参阅getParentProfileInstance()
和DevicePolicyManager
下的参考文档。