会话过期devise模式

我经常不得不应付会话/访问令牌在iOS应用devise中过期,并且从来没有真正发现过我可以100%满意的devise,所以我在这里问这个问题是否有人可以提出更好的devise比我目前使用。

问题

您有一个使用用户名和密码login的应用程序。 服务器返回一个访问令牌,应该用于将来的请求来validation该用户。 在将来某个时间点(未知时间),服务器将使该令牌过期,并且使用该令牌发送的任何请求将返回authentication失败。

由于会话过期而失败后,应用程序应该使用原始凭证重新login并获取新的访问令牌。 然后它可以重试原始请求。

所以想象一下你有一个API来获取需要authentication的新闻文章列表。 stream程可能是这样的:

  1. 用户login和应用程序接收令牌。
  2. 视图控制器刷新新闻文章列表。
    1. API请求是使用附加的标记进行的。
    2. API请求成功,并使用新文章更新视图。
  3. 应用程序已closures,一段时间过去了。
  4. 应用程序打开时,视图控制器要刷新新闻文章的列表。
    1. API请求是使用附加的标记进行的。
    2. API请求失败,因为令牌已过期。
    3. View Controller请求刷新令牌并耐心等待。
    4. 一旦令牌被刷新,API请求被重试。

现在想象这是从应用程序中的多个地方完成的。

我目前如何解决它

我通常做的是将证书存储在NSUserDefaults (如果我不关心这些证书的安全性 – 明显更好地使用keychain),然后在全局pipe理器对象(singleton)上使用这些凭证刷新login当我注意到会议已经过期。 这个全局pipe理器在login状态发生变化时触发通知,以便应用程序的其他部分可以知道在会话过期失败后应该何时重试请求。

我不觉得是对的

那么,我从来没有喜欢pipe理器对象的状态机处理。 每个执行请求的地方都需要保存一些状态,以便知道login刷新正在进行,并在刷新login后重试请求。 还有一个问题,如果刷新失败,因为现在密码错误(用户可能改变了它) – 你可能不想完全注销并且销毁应用程序的所有用户状态,因为你可能只是能够请求新的密码并继续进行。 但全球经理并没有真正涉及到用户界面,所以很难处理要求新login的用户界面。

我想知道答案

我明白,这个问题是特别模糊和概念性的(尽pipe我仍然认为可以在StackOverflow上运行),但我真的很想知道其他人是如何解决这类问题的。 只是解释你如何去处理会话过期,重新尝试从整个应用程序失败的请求,并要求用户新的凭据,如果刷新不起作用。

我想整个事情的症结在于这个问题:

在何处放置由于会话到期而失败的请求的重试逻辑。 我看到这些地方是select:

  1. 在视图控制器级别(即保持一个标志来说,一旦login刷新完成,我们需要重试最后的请求)。
  2. 在API请求级别(即将API请求封装在知道要在刷新login后重试的对象中)。
  3. 在全局loginpipe理器级别(也就是说,当refreshLogin被调用时,在login被刷新后执行)。

不要从死亡中提出这个问题,但是由于没有得到回答,我会给出我的意见。

我为这个场景所做的select是把钥匙存储在keychain中(或者任何地方),然后在每次调用之前,我将一个HTTPClient分类为检查是否刷新。 通过这种方式,我可以识别需要的刷新,执行它,然后在一个步骤中重试所有的调用,并且如果有必要的话,可以发送一个错误块来处理任何用户不能相应刷新的情况。

这似乎与你(或可能是)试图完成的一致。 无需通知或任何爵士乐,您可以编写一次,并在整个应用程序中重复使用,通过发送您的呼叫通过该子类别的HTTPClient。

编辑:请记住,你应该记得允许任何身份validation呼叫通过!

你所问的是如何处理会话到期。 其他人已经回答了你的问题。 但是我想你是在问错误的问题。 让我解释。

我们想要的是iOS上用户会话的devise模式。 我们需要从iOS设备的angular度来看待它:

  1. 用户安装应用程序
  2. 用户使用细节进行身份validation,并返回会话令牌
  3. 应用程序然后将(秘密)会话令牌存储在设备上
  4. 任何未来的请求都包括会话令牌

结论: 为iOSdevise的任何API都不应该过期会话令牌。 只是在设备上保密。

所以从我的经验来看,关于会话过期devise模式的问题的答案基本上是:不要在使用iOS的API时使用会话过期。

其中最大的iOS REST API就是这样做的,我不得不同意。

在你的问题中你提到了两件似乎是答案的东西:

A)应用程序处于数据可能丢失的状态,如果用户没有login。
B)应用程序需要重新login才能保存数据。

如果这些是限制,你应该相应地解决它们:

  1. devise一个可以在本地保存更改的scheme。 跟踪与服务器的同步状态。
  2. 如果login状态发生变化并发生意外事件,请不显眼地提醒用户并给予修复的机会。

在我看来,放置逻辑的正确位置在View Controller级别。

如果我正确理解你的问题,你有一个networkingAPI来处理服务器调用,并返回结果(可能从JSON)到视图控制器。

最好的方法应该是创build一个login视图控制器,用户名/电子邮件和密码字段与应用程序逻辑的其余部分分开。 从服务器接收到OK后,该视图控制器可以被解散,应用程序将按预期stream动。

如果您的令牌失效,则服务器应将错误401返回给您的networkingAPI。 你可以简单地把这个错误封装到一个NSError对象中,并传递给View Controller来处理。

在应用程序中的任何地方,服务器调用都可以返回错误401,并因此向用户道歉并撤回login视图控制器,以强制创build新的令牌。

我希望我帮助。

我的方法类似于'(2)在API请求级别' – 除了将请求封装在一个对象之外,封装了API服务器的整个概念。

因此,我通常最终包装每种types的请求,像这样的asynchronous方法签名:

(对不起,它的C#,不是obj-c(我使用Xamarin.iOS),但概念是相同的 – Action<T>等同于obj-c Blocks )

 void GetLatestNews(GetLatestRequest request, Action<NewsListingResponse> success, Action<Exception> error) void Search(SearchRequest request, Action<SearchResponse> success, Action<Exception> error) 

我通常只是将这些静态方法放在一个静态类(很less有相同types的多个服务器,所以一个静态类将正常工作),但我有时把它们放在一个单例实例类中,以便我可以通过在unit testing的一个嘲弄的例子。

无论如何,现在你的VC客户端代码只是根据需要使用API​​:

 override void ViewDidAppear(bool animated) { SomeNewsSiteApi.GetLatestNews( new GetLatestRequest{Count=20}, response => { // Update table view here }, error => { // Show some error alert }); } 

这样做的好处是这些方法的实现处理发送带有当前令牌的请求,如果失败,获得一个新的令牌,然后用新的令牌重新发送相同的请求,然后最终callback到Action<T> successcallback。 客户端VC代码不知道任何重新获取令牌,所有它知道和关心的是,它正在请求一些数据,并等待响应或错误。

面对同样的问题,从几个月。 我的方法“(2)在API请求级别”

请让我知道,如果你有最好的解决scheme来解决这个问题。 这真的会帮助很多面临这些问题的人。

会话过期时刷新auth令牌是非常大的解决scheme。