Webservice凭据 - OpenID/Android AccountManager?

31

我正在构建一个Web服务,并希望使用用户的Google账户凭证。

该服务运行在GAE上,将拥有一个Web客户端和一个Android原生客户端。

这是我第一次尝试这样的事情,我一直在阅读关于OpenID和Android AccountManager库的内容。

我仍然不确定在我的Datastore中存储用户的选项是什么?我应该使用什么标识符?是否可能在本机Android应用程序上使用OpenID?

任何帮助和/或指针都将不胜感激。谢谢。

4个回答

31

我们在上一个项目中也有类似的需求:GAE后端与GWT前端以及Android / iPhone客户端。此外,我们不希望存储用户凭据。

因此,我们选择使用OpenID,这是一种不幸的Web标准,与移动设备不兼容,但可行。

在GAE端,我们只需启用联合登录即可获得OpenID。

在移动设备上,当用户需要登录时,我们向他们呈现一个OpenID认证器列表(Google、Yahoo等),然后我们打开一个本地浏览器(非嵌入式浏览器),并将用户引导到所选的OpenID身份验证网站。好处是用户的浏览器通常已经记住了用户名/密码,因此这一步只需要用户按下一个按钮即可。

这一切都很简单。现在是棘手的部分: 用户确认登录后,OpenID将重定向回我们的GAE返回URL(在发出请求时需要提供此URL)。在此URL上,我们创建一个自定义URL,例如:

yourappname://usrname#XXXYYYZZZ

其中 XXXYYYZZZZ 代表授权令牌。我们从返回页面获取此令牌,它存储为 ACSID cookie:我们使用一些 JSP 代码读取此 cookie 并将其包装到上面的自定义 URL 中。

然后我们注册我们的 Android 和 iPhone 应用程序来处理 yourappname:// URL,这样当用户单击此链接时,我们的应用程序会被调用并且链接被传递给它。我们从此链接中提取用户名和令牌,并在 REST 请求中使用它来访问 GAE 后端。

如果您有任何问题,我很乐意更新此帖子。

更新:

生产 AppEngine 上的用户会话 cookie 名称为 ACSID,而开发 AppEngine 服务器上的名称为 dev_appserver_login


+1 - 非常详细!自定义URL文本显示什么?是“点击此处返回应用程序”吗?还是类似的内容? - Tal Weiss
它可以显示任何你喜欢的内容。我使用了一个看起来像按钮的“继续...”链接。通过一些JavaScript,你可能可以自动启动应用程序,而无需用户点击链接-我没有尝试过这个,需要进行测试。 - Peter Knego

12

我花了大约一周的时间寻找一种适合且现代化的方法 - 不需要使用网络浏览器,而是使用Android账户管理器。

如果你想使用Google账户和AccountManager来识别用户,你可以:

  1. 通过后台线程通过AccountManager获取他在Google Contacts中的令牌(认证令牌类型为"cp"):

  2. public String getUserToken(Activity activity)
    {
        AccountManager accountManager = AccountManager.get(activity);
        AccountManagerFuture<Bundle> amf = accountManager.getAuthTokenByFeatures("com.google", "cp", null, activity, Bundle.EMPTY, Bundle.EMPTY, null, null );
    
        Bundle bundle = null;
        try {
            bundle = amf.getResult();
            String name = (String) bundle.get(AccountManager.KEY_ACCOUNT_NAME);
            String type = (String) bundle.get(AccountManager.KEY_ACCOUNT_TYPE);
            String token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
            return token;
        } catch (OperationCanceledException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (AuthenticatorException e) {
            e.printStackTrace();
        }
        return null;
    }
    
  3. 将收到的UserToken通过安全通道发送到服务器。

  4. 使用gdata库(Google Data API library)在服务器上通过google验证令牌:

  5. public String getUserId(String token)
    {
        ContactsService contactsService = new ContactsService("Taxi");
        contactsService.setUserToken(token);
    
        IFeed feed = null;
        try {
            feed = contactsService.getFeed(new URL("https://www.google.com/m8/feeds/contacts/default/full?max-results=10000"), ContactFeed.class);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ServiceException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
    
        if (feed == null)
            return null;
    
        String externalId = feed.getId();
        IPerson person = feed.getAuthors().get(0);
        String email = person.getEmail();
        String name = person.getName();
        String nameLang = person.getNameLang();
    
        return externalId;
    }
    
  6. Google令牌可能会过期(通常在一小时后),因此如果您无法在服务器上验证令牌,则必须向客户端发送响应,使令牌失效并获取新的令牌。使用帐户管理器使令牌失效:

  7. public void invalidateUserToken(Context context, String token)
    {
        AccountManager accountManager = AccountManager.get(context);
        accountManager.invalidateAuthToken("com.google", token);
    }
    

在 Gmail 和 Facebook 上,是否能够执行相同的操作(获取要使用的令牌)?如果可以,请在下一个帖子中回答:https://dev59.com/4GbWa4cB1Zd3GeqPUjta。 - android developer
但这并不能解决问题,因为他想要在自己的 Web 服务上使用数据库对用户进行身份验证,所以如果他想要在自己的 Web 服务上进行身份验证,他应该将令牌和他的 Google ID 发送到 Web 服务上,然后 Web 服务应该将令牌发送到 Google 服务器,Google 服务器会返回一个带有 Google ID 的响应,您可以将其与用户发送的 Google ID 进行比较,是吗?你怎么做呢? - Karly
1
我测试了这个解决方案,如果你只需要从用户那里获得一个经过身份验证的电子邮件,它非常有效。好处是你可以在应用程序中完成所有操作,而不需要使用Web浏览器。缺点是,你必须请求编辑用户联系人的权限,这可能会让一些人犹豫不决。有没有人知道一种方法,可以_仅仅_要求身份验证,而不需要请求_授权_? - thomas88wp
@thomas88wp 你可以按照这篇指南进行操作,该指南使用了GAE内置的Google账户授权:http://blog.notdot.net/2010/05/Authenticating-against-App-Engine-from-an-Android-app 。请注意,这仅适用于Google账户,而不是OpenID。 - Nilzor
1
这里有一份更好的指南:http://android-developers.blogspot.no/2013/01/verifying-back-end-calls-from-android.html - Nilzor

3
我认为这篇博客文章完全符合您的要求。这对我很有效。这里发布的两个解决方案都是可行和聪明的,但我认为这正是提问者所要求的。
基本上,您只需使用“ah”范围获取authToken,并将其传递给正确的网页以获取ACSID cookie,这将使您可以访问任何使用UserService进行身份验证的AppEngine页面。

0

该示例未使用OpenID或Xauth,因此无法在GAE上用于对现有Google帐户进行身份验证。据我所见,它使用自己的身份验证方案:简单的POST请求,其中用户名/密码作为标头参数。 - Peter Knego
尽管@peterKnego在第二个建议方面有一定的观点,但第一个链接实际上非常有用。但我同意更多的注意力应该放在制定一个适当的答案上,以我个人的看法。但是要小心不要在将来被投票否决。 - tony gil

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