我正在构建一个网络服务,并想使用用户的谷歌帐户凭据。
该服务在 GAE 上运行,将有一个 Web 客户端和一个 Android 原生客户端。
这是我第一次尝试这样的事情,我一直在阅读 OpenID 和 Android AccountManager 库。
我仍然不确定在将用户存储在我的数据存储区方面有哪些选择。我应该使用什么标识符?是否可以在原生 Android 应用程序上使用 OpenID?
任何帮助和/或指针将不胜感激。谢谢。
我正在构建一个网络服务,并想使用用户的谷歌帐户凭据。
该服务在 GAE 上运行,将有一个 Web 客户端和一个 Android 原生客户端。
这是我第一次尝试这样的事情,我一直在阅读 OpenID 和 Android AccountManager 库。
我仍然不确定在将用户存储在我的数据存储区方面有哪些选择。我应该使用什么标识符?是否可以在原生 Android 应用程序上使用 OpenID?
任何帮助和/或指针将不胜感激。谢谢。
我们对上一个项目有类似的要求:带有 GWT 前端和 Android/iPhone 客户端的 GAE 后端。此外,我们不想存储用户凭据。
所以我们选择使用 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,这样当用户 cliskc 这个链接时,我们的应用程序就会被调用并将链接传递给它。我们从此链接中提取用户名和令牌,并在对 GAE 后端的 REST 请求中使用它。
如果您还有任何问题,我很乐意更新这篇文章。
更新:
生产 AppEngine 上的用户会话 cookie 被命名为ACSID
,而在开发 AppEngine 服务器上它被命名为dev_appserver_login
。
我花了大约一周的时间为此找到了一种合适且现代的外观方式-无需网络浏览器并使用 android 帐户管理器。
如果您想使用 Google 帐户和 AccountManager 来识别用户,您可以:
通过后台线程上的 AccountManager 将他的令牌获取到 Google 联系人(身份验证令牌类型为“cp”) :
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;
}
通过安全通道将收到的 UserToken 传递给服务器。
谷歌使用 gdata 库(谷歌数据 API 库)在服务器上验证令牌:
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;
}
Google 令牌可能会过期(通常在一小时后),因此如果您未能在服务器上验证令牌,则必须将响应发送回客户端,使令牌无效并获取新令牌。使用客户经理使令牌失效:
public void invalidateUserToken(Context context, String token)
{
AccountManager accountManager = AccountManager.get(context);
accountManager.invalidateAuthToken("com.google", token);
}
我认为这篇博文正是你想要的。它对我有用。这里发布的两种解决方案都是可行且聪明的,但我认为这正是提问者所要求的。
本质上,您只是使用“ah”范围获取 authToken,并将其传递到正确的网页以获取 ACSID cookie,该 cookie 将允许您访问任何使用 UserService 进行身份验证的 AppEngine 页面。
http://developer.android.com/search.html#q=AccountManager&t=0
http://developer.android.com/resources/samples/SampleSyncAdapter/index.html 在本页底部,您将找到所有需要的代码
此致