我目前正在开发我的第一个原生 iPhone 应用程序(尽管我有多年的网络开发经验)。我在理解处理登录的最佳方式时遇到了一些困难,我正在寻找一些关于最佳方式的建议。我对登录过程中可能出错的所有事情想得越多,我的大脑就越想从我的脑海中跳出来。我对此感到非常沮丧,并且真的可以使用一些更有经验的 iPhone 开发人员的建议。在此先感谢您的帮助。
我的目标是在应用程序的第一个版本中支持 Facebook Connect,然后在以后的版本中支持其他 SSO 服务(Twitter、Google 等)以及我自己的用户帐户系统。当前的计划是在服务器上创建一个 MySQL 表,如下所示:
users (id, nickname, facebook_id, ...)
当用户第一次通过 Facebook 登录应用程序时,将在此表中为他们创建一个条目。您可能认为这没有必要,但它可以让我稍后扩展到其他服务。例如,我可以这样做:
users (id, nickname, facebook_id, twitter_id, google_id, username, ...)
此表将包含 facebook_id、twitter_id、google_id 和用户名的可为空字段。如果用户使用 facebook 登录,他们将拥有一个 facebook_id。Twitter 用户将拥有一个 twitter_id,Google 用户将拥有一个 google_id,而我自己的用户将拥有一个用户名。无论他们使用什么登录系统,他们都将由我自己的 ID 唯一标识。
所以我对用户帐户的后端实现非常满意。我可以设置应用程序可以调用的 Web 服务来创建/检索用户、验证登录等。没问题。
我遇到的问题是使用 iPhone UI 组件实现正确的登录流程。我的特定应用程序使用用作主导航的 UITabBarController。其中一个标签被标记为“我的帐户”,并包含有关当前登录用户的信息。如果用户单击“我的帐户”选项卡,他们会看到一个用作子菜单的表格视图。它有“我的个人资料”、“设置”等选项。如果他们点击了这些菜单项中的任何一个并且他们没有登录,那么我使用presentViewController函数来弹出一个登录屏幕。他们单击“使用 facebook 登录”并通过典型的 Facebook 授权过程。当他们完成该过程后,我使用dismissViewController删除登录页面并显示他们尝试访问的页面。如果他们取消登录或登录失败,那么我使用UINavigationController 上的popViewControllerAnimated将它们发送回“我的帐户”子菜单。对于那些难以想象这一点的人,请查看亚马逊应用程序。这几乎完全相同(只需在未登录时单击“更多”选项卡并尝试单击其下方的菜单项之一)。
这一切都很好,我很满意。但这是我感到困惑的地方:
如果他们在“我的帐户”选项卡中深入到 UINavigationController 的几个级别并且他们的登录会话到期,我该怎么办?
让我们以 Facebook 登录为例。Facebook 使用会话令牌来保持用户登录。令牌会在一定时间后过期。假设用户向下导航到“我的帐户”,然后单击“我的个人资料”,然后单击“编辑”并显示一个屏幕,他们可以在其中编辑他们的个人资料信息。因此,他们显然需要经过身份验证才能查看此页面。事实上,它们深入到需要经过身份验证才能看到的页面的 2-3 层。现在假设他们被电话或其他事情打断,忘记了他们在做什么。他们下次访问该应用程序的时间是一周后,此时他们的登录会话已过期。我可以通过几种方式处理这个问题。在我看来,它们都不是很好。
解决方案#1
Facebook SDK 将自动调用 AppDelegate 类上的一个方法,通知我会话已过期。由于我在 AppDelegate 级别收到会话到期通知,因此我不知道用户当前正在查看的页面以及他们是否需要进行身份验证才能使用它。为了解决这个问题,我可以让所有需要登录的 ViewController 扩展“ProtectedViewController”类或指示用户应该登录才能看到该页面的东西。然后当 AppDelegate 收到会话过期的通知时,它会尝试找出当前的 ViewController 是什么,并检查它是否扩展了“ProtectedViewController”。如果是,则显示一个登录屏幕。如果用户成功登录,那么一切都会正常进行。如果不,然后将用户返回到他们必须从头开始的应用程序的第一个屏幕。这很糟糕,因为用户将丢失他们已经输入的任何内容,但我看不出有任何方法可以使用此解决方案来避免它。
解决方案#2
忽略 AppDelegate 级别的会话过期事件,而是执行以下操作:在采取任何需要用户登录的操作之前(例如,当用户在其“编辑配置文件”页面上单击“保存”时),检查他们是否仍然已登录。如果未登录,则显示登录屏幕。如果用户无法登录,则将其发送回开始屏幕。这个解决方案对代码来说很麻烦,因为我必须检查用户在应用程序的受保护区域内所做的几乎所有事情——当他们查看页面时,当他们点击按钮时——几乎所有事情。
如果用户无法重新进行身份验证,我也希望避免将用户一直返回到应用程序的开始屏幕。相反,在这种情况下,我更愿意将用户返回 UINavigationController 到“我的帐户”菜单——这是最近的不需要登录的页面。当然,我可以对其进行硬编码,但我正在寻找一种更自然地工作并且可以在其他应用程序中重用的解决方案/模式。
我真的很感激一些指导。当然,我不是世界上第一个需要解决这个问题的人。不幸的是,谷歌并没有提供太多帮助。
谢谢。
编辑:另一个想法是继承 UIViewController(例如“ProtectedViewController”)并实现“viewWillAppear”方法。在此方法中,我可以检查用户是否已登录。如果没有,则向上滑动登录页面。不过,当他们无法登录时,我仍然不知道如何处理这种情况。但是,这个解决方案有一个问题:如果用户的会话在他们使用应用程序时过期,那么我不会重新验证他们,直到他们下次单击新视图时。如果他们已经在查看“编辑”页面并单击“保存”按钮,那么他们将不会被重新验证。但也许这离解决方案更近了一步。