最不侵入式的方式唯一标识Android用户是什么?

25

如何唯一地识别已安装您的应用程序的用户,以便:

  1. 如果他们删除并重新安装您的应用程序,您将知道是他们;
  2. 如果他们在第二个设备上同时安装您的应用程序,您将知道是他们?

以 Netflix 应用程序为例,它会自动链接到您的桌面帐户,无需任何用户交互。我猜测他们使用 accountManager.getAccounts() 或类似的方法,因为他们还需要 GET_ACCOUNTS 权限。但是当然,该权限标记为 保护级别:危险。是否有任何 less invasive 或潜在令人担忧的技术来实现这一点?


回答这个问题的关键是既简单(对于用户),又尽可能少干扰用户。Android 提供了很多识别用户的方法,其中很多方法涉及突破用户的隐私,如果那是唯一的方法,我就会像现在一样(可选的电子邮件注册)。我只是想让我的应用程序知道,一个用户是否已经在我的系统中注册,不需要进行采访(用户名/密码、电子邮件地址、第三方 OAuth 等)。

我主要的原因是:

  1. 我不希望收到用户在重新安装后留下来的托管内容的支持请求;以及
  2. 我不想托管大量的孤立内容。

我认为这就是GET_ACCOUNTS被标记为“危险”级别的原因之一。如果您根据帐户跟踪谁安装了应用程序,那么您可能会收集个人信息。而且,尽管使用相同的链接帐户,但同时使用的设备基本上没有任何连接,我想不出任何方法。 - chris-pollux
我完全同意。然而,在这里,使用案例非常普遍——想象一下一个照片应用程序。用户安装应用程序,我创建一个帐户,他们创建内容,我将其与他们的帐户关联——其中一些是私有的,一些是共享的。我希望帐户在设备之间持久存在,而不会用“可怕的权限”吓到用户。我希望Android有一个“GUID”,对于每个发布者,它都是唯一的,这样com.mycompany.app1com.mycompany.app2就可以看到相同的值或类似的东西。但我可以理解为什么目前这样做行不通。 - Andrew
在这种情况下,你说得对,这会很有用。另一方面,它也可能会让用户感到害怕,因为他们的部分私人内容会“神奇地”出现在另一台设备上。 也许如果您在权限请求期间彻底解释权限,这将有助于消除恐惧感。这还将允许用户选择是否希望将其内容限制在一个设备上。 - chris-pollux
也许使用Digits的短信认证比通过社交网络使用OAuth更为可接受?仅为建议。 - Dmytro Rostopira
1
@tar,恕我直言,这个问题有很多变体,但我的确切问题与a)最小权限(不要惊动用户)和b)尊重用户隐私有关。如果您能在SO上找到这个确切的问题,请在下面发布或标记为重复。如果您不同意这就是我所问的问题,我不知道该建议什么。我已经尽力让这个问题尽可能清晰明了。 - Andrew
显示剩余2条评论
6个回答

10
请看一下Firebase身份验证。它非常无缝,不需要太多努力即可使用。而且对最终用户来说,没有什么干扰性或繁琐性。

这是Google的视频教程

编辑: 如果您的用户肯定拥有带有电话号码的移动设备,则可以使用AccountKit。这也是他们所谓的OTA(一次性验证)。AccountKit仅使用用户的电话号码来验证和验证用户。

编辑: Firebase身份验证现在具有“电话验证”功能,类似于上面提到的AccountKit。两者都是不错的服务。但是,Firebase电话验证允许您从头开始制作自己的UI(这意味着比AccountKit更好的控制)。此外,如果您不想制作自己的UI,则始终可以使用FirebaseUI


2
我会接受这个答案,因为我认为它让我离我的目标最近,尽管下面还有一些非常有趣的想法。@assem-mahrous建议的跨设备通知系统最有趣(虽然我不确定它是否在安装过程中是持久/确定性的)。对我决定的是Firebase允许“匿名登录”,所以用户可以立即进入应用程序,探索,建立自己的内容,然后当他们感到投入并信任它时,他们可以将身份升级到他们的Google帐户(或FB或电子邮件/密码)。而且他们可以强制执行单一帐户。 - Andrew
2
@Andrew 当您向用户发送推送时,您可以获取一个卸载您的应用程序的用户数组,通过静默推送在您的应用程序中处理它,以便不会向用户显示任何通知,您只需获得成功和失败的响应。 - Assem Mahrous

4

我实现了一个似乎与你的东西类似的东西,使用推送通知,如果用户卸载了我的应用程序(根据注册ID获取用户),我会收到错误信息。如果他重新安装,就会获得一个新的注册ID,并尝试为不同设备获取用户UUID。


谢谢你的回复。你是使用Firebase还是仍然使用GCM来接收UID?另外,你知道未经身份验证的用户是否会在她拥有的两个设备(例如手机和平板电脑)上收到相同的UID吗?我相信这在公共API中是不可能的,但如果Google使用私有API,那么这可能是可能的。 - Andrew
Firebase在我的Laravel后端上实现,每个用户都会获得一个唯一的令牌。如果他卸载并重新安装应用程序,他将获得一个新的令牌,唯一的东西是UUID,我甚至在注册我的应用程序之前就获取它以便能够跟踪他。 - Assem Mahrous

3

我认为最简单的方法是使用UUID并将其哈希存储在sharedPreferences中。您应该尽早在您的应用程序中生成UUID。

sharedPrefs = context.getSharedPreferences(APP_SHARED_PREFS,Activity.MODE_PRIVATE);
if (sharedPrefs.getString("YOUR-KEY-TO-THE-UUID") == null || "".equals(sharedPrefs.getString("YOUR-KEY-TO-THE-UUID"))){
    prefsEditor = sharedPrefs.edit();
    prefsEditor.putString("YOUR-KEY-TO-THE-UUID", UUID.randomUUID().toString());
    prefsEditor.commit();
}

如果用户从设备中卸载应用程序,则此方法将无法工作。如果用户卸载应用程序,SharedPreference数据将被删除。 - dev_kj

1

我认为最好的方式是使用GoogleFacebook实现登录。这对用户来说非常无缝,足够安全(因为Google和Facebook被认为是可信的),您不需要实现电子邮件注册,而且您将在各个设备上都有身份认证。


谢谢你的回答。如果他们没有谷歌/脸书,我想我可以使用Twitter。没有Twitter?那就用Foursquare。没有Foursquare?那就用微博。然后是Etsy、Fitbit、Mixi和Netflix。这是一条无限回归的路径。然后还有一个问题,用户是否愿意将他们的OAuth身份与您连接起来,以及如果您愿意将您的应用程序和用户群体连接到该提供商。我个人从不感觉点击那个按钮很舒服(SO是我目前唯一在任何地方连接的东西)。我认为它放弃了太多,而回报太少。 - Andrew
这取决于您,我只是建议最安全且在大多数情况下有效的选项。 - Alex Radzishevsky
1
@Andrew,按照你的想法,任何事情都不会对你起作用。如果你拥有Android设备,无论如何都必须使用Google账户进行设置。如果有人正在运行一些奇怪的rooted Android镜像,并且没有Facebook或Twitter账户,那么我们已经在大海捞针了。这绝对不是无限回归。如果用户没有这些账户中的任何一个,您可以为他们提供几个简单的选项,让他们使用电子邮件注册。哦,如果他们没有电子邮件呢? :) 你知道我在说什么吧? - Andrej Jurkin
@AndrejJurkin,我理解人们对此的烦恼,也明白你的意思。我只是试图找到最佳平衡点,在功能、易用性、支持易用性和隐私方面,我看到了一些好的建议。我总是感到失望,但并不惊讶,很多开发者从未考虑过社交登录的隐私成本。而且,在国际上,这肯定是无限回归:Facebook在中国被封锁;微博在非洲闻所未闻;Twitter在中东经常被封锁。此外,大多数社交网站允许您删除链接的应用程序,这对用户隐私非常有利,但对支持来说则是一个“脚枪”。 - Andrew
1
@Andrew,使用Google登录的���本到底是什么呢?😊你总是知�自己将�分享什么信�,如��喜欢需求,那么这个应用�能就�适�你。默认情况下,你�会分享基本的信�。�当我在应用中看到Google或者FB的登录按钮时,我都感到很高兴,这样我就能快速设置账�,而�是浪费时间填写一些注册表格。 - Andrej Jurkin
@AndrejJurkin Google登录不是太大的问题,因为他们拥有生态系统,但我希望FB和Twitter更加明显。但是,即使使用Google,一些人(包括我有时候)会问一个合理的问题,为什么你的应用程序需要知道关于我的任何事情?在这种情况下,我有一个技术动机。我可以在常见问题解答中向用户解释,但每段话都会让我额外花费翻译费用。我宁愿它“只是工作”,并且不会在任何人的脑海中引起疑虑。给人们没有理由不信任你。而注册表格也不是唯一的选择。 - Andrew

1
如果你的应用仅限于Android系统,并且希望为用户提供身份验证而不需要创建账户,我认为使用Google账户名称/ID是最好的选择(通过Android访问Google账户ID/用户名),因为在Android手机上必须使用Google账户(除非你对其进行了root操作、删除了Google Play服务等)。如果你只想解决问题的第一个点(重新安装后识别用户身份),则可以使用设备ID-Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID);虽然它不是100%可靠(例如出厂设置会重置此值)。

谢谢你的回答。我认为Secure.ANDROID_ID越来越接近符合我在重新安装应用程序或清除设备数据方面的关注点的答案,尽管工厂重置问题确实是一件麻烦事。我假设单个用户的ADROID_ID会因设备而异。 - Andrew

0
通过使用 JSON web tokens (JWT) 与标准的RESTful API交互,可以实现此类功能的标准。
假设您的安卓应用程序与 RESTful API 交互以进行所有 CRUD 操作和业务逻辑,则使用 JWT 作为身份验证标识符可非常有效。您可以在每个 JWT 中嵌入信息,从而允许您标识任何您喜欢的内容(数据库中的用户 ID、用户登录位置的设备 ID 等)。JWT 实质上是一种数据结构,允许您存储要由 API 使用的信息。
以下是一些基本原理:
  1. 将JWT传递到应用程序中:用户使用用户名/密码登录应用程序。然后,API返回一个加密的JWT,供客户端在以后的所有请求中使用。不要尝试自己进行加密。任何能够处理API服务的语言都会有相应的库。
  2. 使用JWT中的信息:JWT本身就是一种数据结构。例如,它可能看起来像这样:

    { user_id: 1, device_id: 44215, device_os: android, }

    当JWT通过请求头进行身份验证时,您的API将对其进行解密,然后在会话的上下文中提供该信息。

如果您提供了API使用的语言,则我可能会推荐一个库。

最后,我想谈谈您提交的最终要求,即您不想在安装过程中对用户进行面试。如果我理解您的意思,您希望用户能够简单地安装应用程序并开始使用,而无需提供身份验证凭据,那么没有安全的方法可以实现这一点。您可能能够想出一种hackish的方法使其工作,但它将从根本上不安全。


JWT可以很好地在会话之间维护状态(尽管正如许多人在其他地方解释的那样,JWT在维护状态持久性方面较差)。但我的问题是关于在新实例之间维护身份。这正是我的问题,我已经提供了一种由NetFlix安全且非黑客方式完成的方法。 - Andrew
当Netflix检测到您已安装桌面版本(或在Android应用程序中检测到已安装Android应用程序)时,然后使用在该应用程序中找到的凭据通过浏览器授予访问权限,几乎肯定是简单地从本地应用程序检索JWT并使用其进行身份验证。它可能会请求一个新的唯一令牌来区分自己和桌面应用程序以进行分析,但重点是出于安全考虑,您需要至少在每个设备上对用户进行一次访谈。 - melchoir55
如果您的关注点仅是在应用程序安装之间保留JWT,则必须将数据存储在“正常”应用程序之外。例如,您可以在SD卡或文件系统上创建一个加密文件。 - melchoir55
FS存储绝对是其中一种解决方案。我认为它和Secure.ANDROID_ID所提供的优缺点相同,唯独多了一个“危险级别保护”标记着必需权限。就个人而言,我比较倾向于使用WRITE_EXTERNAL_STORAGE权限而不是GET_ACCOUNTS,因为如此多的应用程序都在使用它,当我安装某些应用时,我几乎期望看到它。 - Andrew
我不会使用Secure.ANDROID_ID来实现这个。首先,在我看来,这样做是不安全的。其次,正如你所建议的那样,从权限的角度来看,写入文件系统似乎要少得多。第三,即使忽略安全性问题,它也不够可靠。该值在不常见的情况下可能会发生变化,并且通常不像您自己的文件系统实现那样可靠。 - melchoir55

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接