Web 服务凭证 - OpenID/Android AccountManager?

发布于 2024-09-11 14:01:56 字数 256 浏览 12 评论 0原文

我正在构建一个网络服务,并想使用用户的谷歌帐户凭据。

该服务在 GAE 上运行,并将有一个 Web 客户端和一个 Android 本机客户端。

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

我仍然不确定在数据存储中存储用户时有什么选择。我应该使用什么标识符?是否可以在本机 Android 应用程序上使用 OpenID?

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

I'm building a webservice and would like to use the user's google account credentials.

The service runs on GAE and will have a web client and an Android native client.

This is my first attempt of something like this and I've been reading about OpenID and the Android AccountManager library.

I'm still not sure what are my options in terms of storing the users in my Datastore. What Identifier should I use ? Is it possible to use OpenID on a native Android application ?

Any help and/or pointers would be appreciated. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

随风而去 2024-09-18 14:01:56

我们对上一个项目有类似的要求:带有 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,以便当用户点击此链接时,我们的应用程序被调用并将链接传递给它。我们从此链接中提取用户名和令牌,并在对 GAE 后端的 REST 请求中使用它。

如果您还有其他问题,我很乐意更新这篇文章。

更新

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

We had a similar requirements on the last project: GAE backend with GWT frontend and Android/iPhone clients. Also, we did not want to store user credentials.

So we choose to use OpenID, which is unfortunately a Web standard and does not play well with mobile devices, but is doable.

On the GAE side we simply enabled federated login which gave us OpenID.

On mobile devices, when user needs to login we present to them a list op OpenID authenticators (Google, Yahoo, etc..). Then we open a native browser (not embedded browser) and direct user to chosen OpenID authentication site. The upside is that user's browser usually already has username/pass remembered, so this step just requires user to press one button.

This is all pretty straightforward. Now here is the tricky part:
After user confirms login, OpenID redirects back to our GAE return url (you need to provide this url when request is made). On this url we create a custom URL, for example:

yourappname://usrname#XXXYYYZZZ

where XXXYYYZZZZ is auth token. We get this token from the return page where it's stored as an ACSID cookie: we used some JSP to read this cookie and wrap it into above custom URL.

Then we register our Android and iPhone apps to handle the yourappname:// URLs, so that when user cliskc this link, our app is invoked and the link is passed to it. We extract user name and token from this link and we use it in REST requests to the GAE backend.

If you have any more questions I'd gladly update this post.

Update:

The user session cookie on production AppEngine is named ACSID, while on development AppEngine server it's named dev_appserver_login.

他是夢罘是命 2024-09-18 14:01:56

我花了大约一周的时间找到了一种合适且现代的方式来实现此目的 - 无需网络浏览器并使用 Android 帐户管理器。

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

  1. 通过 后台 线程上的 AccountManager 将其令牌获取到 Google 通讯录(身份验证令牌类型为“cp”):

    public String getUserToken(活动活动)
    {
        AccountManager accountManager = AccountManager.get(activity);
        AccountManagerFuture<捆绑> amf = accountManager.getAuthTokenByFeatures("com.google", "cp", null, 活动, Bundle.EMPTY, Bundle.EMPTY, null, null );
    
        捆绑包 = null;
        尝试 {
            捆绑= amf.getResult();
            字符串名称=(字符串)bundle.get(AccountManager.KEY_ACCOUNT_NAME);
            字符串类型=(String)bundle.get(AccountManager.KEY_ACCOUNT_TYPE);
            字符串令牌=bundle.getString(AccountManager.KEY_AUTHTOKEN);
            返回令牌;
        } catch (OperationCanceledException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (AuthenticatorException e) {
            e.printStackTrace();
        }
        返回空值;
    }
    
  2. 通过安全的方式将收到的 UserToken 传递到服务器 频道。

  3. Google 使用 gdata 库 (Google 数据API 库):

    public String getUserId(String token)
    {
        ContactsService contactsService = new ContactsService("出租车");
        contactService.setUserToken(令牌);
    
        IFeed feed = null;
        尝试 {
            feed = contactService.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();
        }
    
        如果(饲料==空)
            返回空值;
    
        String externalId = feed.getId();
        IPerson person = feed.getAuthors().get(0);
        字符串电子邮件= person.getEmail();
        字符串名称 = person.getName();
        String nameLang = person.getNameLang();
    
        返回外部ID;
    }
    
  4. Google 令牌可能会过期(通常在一小时后),因此如果您在服务器上验证令牌失败,则必须将响应发送回客户端,使令牌无效并获得一个新的。使用账户管理器使令牌失效:

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

I spent about a week to find a suitable and modern looking way for this - without web browser and by using android account manager.

If you would like to use Google account and AccountManager to identify the user you can:

  1. Get his token to Google Contacts (auth token type is "cp") through AccountManager on background thread:

    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;
    }
    
  2. Pass received UserToken to the server over secured channel.

  3. Validate the token at the server by google using gdata library (Google Data API library):

    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;
    }
    
  4. Google token can expire (usually after an hour), so if you failed to validate the token at the server, you must send response back to client, invalidate the token and get a new one. Use account manager to invalidate the token:

    public void invalidateUserToken(Context context, String token)
    {
        AccountManager accountManager = AccountManager.get(context);
        accountManager.invalidateAuthToken("com.google", token);
    }
    
眼眸 2024-09-18 14:01:56

我认为这篇博客文章正是你想要的。这对我有用。这里发布的两种解决方案都是可行且聪明的,但我认为这完全符合提问者的要求。

本质上,您只是使用“ah”范围获取 authToken,并将其传递到正确的网页以获取 ACSID cookie,该 cookie 将允许您访问任何使用 UserService 进行身份验证的 AppEngine 页面。

I think this blog post does exactly what you want. It worked for me. Both of the solutions posted here are viable and clever, but I think this does it exactly how the asker was asking.

Essentially, you're just getting an authToken using the "ah" scope, and passing it to the right webpage to get the ACSID cookie that will let you access any AppEngine page that uses UserService for authentication.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文