简体   繁体   English

在Android上的我的应用之间共享oauth令牌-共享的用户ID,钥匙串,AccountManager或其他?

[英]Sharing oauth token between my apps on Android - Shared User ID, Keychain, AccountManager or something else?

I'm trying to work out the best solution for a particular situation I'm in, and am having trouble working out the best option. 我正在尝试针对所处的特定情况制定最佳解决方案,但在寻找最佳选择时遇到了麻烦。 It's a tricky setup, so might be a fun challenge for you Android experts! 这是一个棘手的设置,因此对于您的Android专家来说可能是一个有趣的挑战! Here's my situation: 这是我的情况:

  • We have two Android apps already on the Play Store, and are working on another right now. 我们已经在Play商店中提供了两个Android应用,并且现在正在开发另一个。
  • The two released apps are signed with the same keystore, but do not currently have a sharedUserId set in their manifest files. 这两个已发布的应用程序使用相同的密钥库签名,但是当前在其清单文件中未设置sharedUserId。
  • The two released apps store a user's oAuth token in SharedPrefs, some product/content data in an SQLite DB, and some audio/video content in external storage (using getExternalFilesDir). 这两个已发布的应用程序在SharedPrefs中存储用户的oAuth令牌,在SQLite DB中存储一些产品/内容数据,在外部存储中存储一些音频/视频内容(使用getExternalFilesDir)。
  • The apps are all separate oAuth clients/applications of our server (ie they all use different client ID and secret keys). 这些应用程序都是我们服务器的独立oAuth客户端/应用程序(即它们都使用不同的客户端ID和密钥)。
  • Our server is setup to only allow one oAuth token per oAuth application (ie Android app). 我们的服务器设置为每个oAuth应用程序(即Android应用程序)仅允许一个oAuth令牌。 eg if a user logs in to app A on one device, then logs into app A on another device, the first device's token will be invalidated and the app will receive a 401. 例如,如果用户在一个设备上登录到应用程序A,然后在另一台设备上登录到应用程序A,则第一个设备的令牌将失效,并且该应用程序将收到401。
  • We've successfully implemented a single sign-on system on iOS by enabling shared keychain between the apps. 通过启用应用之间的共享钥匙串,我们已经在iOS上成功实现了单点登录系统。 If an app detects that another app in the group has a valid oAuth token, it can send that to our server and exchange it for a valid token for that app. 如果某个应用程序检测到组中的另一个应用程序具有有效的oAuth令牌,则可以将其发送到我们的服务器,并将其交换为该应用程序的有效令牌。
  • In the iOS version, we wanted to ensure that the apps didn't need to know about the existence of the other apps using hardcoded values per-app (eg if we release a new app in the future, other apps don't need to be updated to share/receive tokens with it), so we created an entry in the keychain containing an array of bundle IDs that had valid tokens, that all apps could access. 在iOS版本中,我们要确保这些应用程序不需要使用每个应用程序的硬编码值来了解其他应用程序的存在(例如,如果将来我们发布一个新应用程序,则其他应用程序不需要进行更新以与之共享/接收令牌),因此我们在钥匙串中创建了一个条目,其中包含具有有效令牌的捆绑ID数组,所有应用程序都可以访问该令牌。 When an app successfully logs in or exchanges a token, they add their own bundle ID to that array. 当应用程序成功登录或交换令牌时,他们会将自己的捆绑包ID添加到该阵列。 Any newly installed app could find a bundle ID from that array, and use that it as a key for loading the token details for that app, which it would then exchange for its own fresh token. 任何新安装的应用程序都可以从该阵列中找到捆绑软件ID,并将其用作加载该应用程序令牌详细信息的密钥,然后它将交换其自己的新令牌。
  • We want the token exchange to be automatic and not require input from the user. 我们希望令牌交换是自动的,并且不需要用户输入。

I hope that all makes sense!!! 我希望一切都有意义!!! Please let me know if not. 如果没有,请通知我。

I'm now trying to work out the best method for storing oAuth tokens (plus some additional data such as email address to go with it) on Android so that other apps owned by our account can access them in order to exchange for a fresh token. 我现在正在尝试找出在Android上存储oAuth令牌(以及一些其他数据,例如电子邮件地址)的最佳方法,以便我们帐户拥有的其他应用可以访问它们,以换取新的令牌。

I've looked into using the following, but am unsure of the best route: 我已经研究过使用以下方法,但是不确定最佳方法:

  1. SharedPreferences along with sharedUserId SharedPreferences和sharedUserId
  2. AccountManager ( https://developer.android.com/reference/android/accounts/AccountManager.html ) AccountManager( https://developer.android.com/reference/android/accounts/AccountManager.html
  3. Android Keychain ( https://developer.android.com/reference/android/security/KeyChain.html ) Android钥匙串( https://developer.android.com/reference/android/security/KeyChain.html
  4. ContentProviders ContentProviders

The problem with option 1. seems to be that setting the sharedUserId after first release will lose access to all of the data (see http://java-hamster.blogspot.jp/2010/05/androids-shareduserid.html ). 选项1的问题似乎是,在第一个发行版之后设置了sharedUserId将会失去对所有数据的访问权限(请参阅http://java-hamster.blogspot.jp/2010/05/androids-shareduserid.html )。 This is not a nice thing for our users. 对于我们的用户来说,这不是一件好事。

Option 2. (AccountManager) could be a good option, but if we want to store the tokens separately (per-app), but want any other apps we make to access their tokens, I'm not sure how we'd do that. 选项2。(AccountManager)可能是一个不错的选择,但是如果我们想分别存储令牌(每个应用程序),但又想让我们制造的任何其他应用程序访问其令牌,我不确定该怎么做。 。

Option 3... is it possible to do what we need with Keychain? 选项3 ...使用钥匙串可以做我们需要做的事情吗?

If I understand correctly, option 4 would need each app to have its own ContentProvider? 如果我理解正确,选项4是否需要每个应用程序都有其自己的ContentProvider? I'm not sure how that would work for our requirements. 我不确定这将如何满足我们的要求。

If anyone has gone through this kind of situation and could share some insights and recommendations, I'd really appreciate it! 如果有人遇到这种情况并可以分享一些见解和建议,我将非常感谢!

AccountManager is meant to solve the exact problem that your are commenting. AccountManager旨在解决您正在评论的确切问题。 Here is a good tutorial to work with it: http://blog.udinic.com/2013/04/24/write-your-own-android-authenticator/ 这是一个与之配合使用的好教程: http : //blog.udinic.com/2013/04/24/write-your-own-android-authenticator/

Just be sure that you sign all your apps with the same keystore, because this is the only thing that might complicate things (a lot). 只要确保您使用相同的密钥库对所有应用程序进行签名即可,因为这是唯一使事情复杂化的事情。

Using preferences will lead you into a problem as all that you store in the main thread is not guaranteed to be there in a Service (like a SyncAdapter). 使用首选项会导致您遇到问题,因为不能保证您存储在主线程中的所有内容都可以在Service(如SyncAdapter)中找到。 There used to be a trick for this in the form of flag (MULTI_SERVICE) but was deprecated in api 23. 过去曾经以标记(MULTI_SERVICE)的形式使用此技巧,但在api 23中已弃用。

ContentProvider is of course possible (its too generic) but AccountManager will help you to cover the corner cases related from refreshing tokens and other interesting stuff. ContentProvider当然是可能的(它太通用了),但是AccountManager将帮助您解决与刷新令牌和其他有趣内容有关的特殊情况。

ContentProvider is probably your best best. ContentProvider可能是您最好的。 I won't be able to provide the whole code for you to do this, but this is generally how I see it working: 我将无法为您提供完整的代码,但这是我通常认为的工作方式:

  1. Each app creates a content provider that exposes their own API token; 每个应用程序都会创建一个内容提供程序,以公开其自己的API令牌;
  2. Each app tries to acquire and query (sequentially until successful) all the other content providers before requesting a login; 每个应用尝试在请求登录之前尝试获取并查询(依次直到成功)所有其他内容提供商;
  3. If app X is able to acquire and retrieve the token from app Y (via Y's content provider), then store it in app X and use it; 如果应用X能够(通过Y的内容提供商)从应用Y获取和检索令牌,则将其存储在应用X中并使用它;

Side notes: 旁注:

  1. This is very sensitive information, so you should enforce security. 这是非常敏感的信息,因此您应该强制执行安全性。 Your content providers should only be accessed by other apps signed with the same key, they should have only read permissions and you should create your own custom permission as well. 您的内容提供商只能由使用相同密钥签名的其他应用程序访问,它们应该仅具有读取权限,并且您还应该创建自己的自定义权限。
  2. The content provider does not need to access an sqlite database. 内容提供商不需要访问sqlite数据库。 It can access whatever your using to store the token (which I hope is stored in a secure way, but I'll leave that to your own judgment) 它可以访问您用来存储令牌的任何内容(我希望以安全的方式存储令牌,但是我将自己决定)

Useful links: 有用的链接:

  1. How to create a custom content provider 如何创建自定义内容提供商

  2. How to secure your content provider 如何保护内容提供商

  3. Example of content provider that retrieves data from shared preferences; 内容提供者从共享首选项中检索数据的示例;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM