jjzjj

关于android:何时用刷新令牌交换访问令牌

codeneng 2023-03-28 原文

When to exchange access token with refresh token

我理解使用 OAuth2 的流程是:

在短期访问令牌过期后(服务器返回 401),客户端必须使用刷新令牌请求新的。

要在 iOS(使用 AFNetworking)或 Android(使用 Volley)应用程序中实现它,我想网络管理器必须能够检测返回的 401 错误,然后向身份验证服务器发送请求。

问题在于网络的并发使用。考虑访问已过期的场景,应用程序发送 2 个请求:req1 和 100 毫秒后,req2。绘制在时间轴上,如下所示:

1
2
req1 --> 401 --> (refresh req) --> OK, new access and fresh tokens --> retry req1
  req2 --> 401 --> (refresh req) --> 403, wrong refresh token

最终的结果是req2会失败,应用会因为403错误退出用户。

所以我的问题是

这个实现是否朝着正确的方向发展?还是收到401后刷新不对?我是否应该在用户启动应用程序时刷新令牌(以减慢应用程序启动为代价)

如何解决并发问题?

  • 您在android中使用哪个库进行api调用?
  • @ChandrakantDvivedi 我正在使用 Volley
  • 我正在使用 okHttp,其中提供了拦截器,您可以在其中拦截请求和响应。
  • Volley 也可以,问题是如何兑换代币
  • 您需要使用 refretoken 生成新令牌,并且必须更新原始请求标头,并且再次需要使用新的 accesstoken 请求服务器。在拦截器中
  • 我理解,但这不是我的问题。我遇到了并发问题。
  • @Siyu您是否已经有一些适用于顺序请求但可能在并行请求上失败的令牌管理器实现?
  • @JánHala??是的。如果我一个一个发送请求,它会起作用


由于您有一个现有的令牌管理器,我会在其中添加一些额外的逻辑(在 Java 中):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class TokenManager {

  private String accessToken;
  private CompletableFuture<String> accessTokenRefreshComletableFuture;

  public CompletableFuture<String> getAccessToken() {
    if (this.accessToken is expired) {
       // If refreshed accessToken is being requested
       CompletableFuture<String> runningRequestFuture = this.accessTokenRefreshComletableFuture;
       if (runningRequestFuture == null) {
          // For thread safety, this assignment should be synchronized (or made atomic)
          // with the previous reading
          this.accessTokenRefreshComletableFuture = new CompletableFuture<>();
          // Request a fresh access token.
          // When you get a new access token, set the this.accessTokenRefreshComletableFuture
          // complete and remove its reference from the manager class.
       }
       return runningRequestFuture;
    }
    // Synchronous result
    return CompletableFuture.completedFuture(this.accessToken);
  }
}

管理器不返回访问令牌,而是返回 CompletableFuture(JavaScript 中的 Promise - 异步结果)。如果需要刷新访问令牌,请先检查 /token 端点请求是否已在运行。如果是,则返回它的 CompletableFuture.

这样,您将始终拥有一个有效的访问令牌或单个 CompletableFuture 等待新的访问令牌。

  • 所以这个想法是在发送任何请求之前检查令牌?
  • 是的,我认为在发送之前检查它是件好事——它更快,并且您可以避免太多被禁止的请求访问服务器。但是,如果您从资源服务器获得 HTTP 403,您应该使用刷新的访问令牌重试。
  • 好的,但是如果我确实收到了 403,我该如何避免遇到我帖子中描述的情况?
  • 对不起,我的意思是 HTTP 401 - 然后你会得到一个刷新的访问令牌。您不应收到 HTTP 403 - req1 将要求刷新令牌并等待它返回,而 req2 将检测到等待刷新的令牌。然后他们都将使用相同的有效访问令牌。
  • 抱歉,我对此有点固执,但是我如何检测到 req1 正在请求新令牌并阻止 req2?
  • Req1 将要求 TokenManager 获取新的访问令牌。 TokenManager 将返回一个 CompletableFuture。当 req2 请求新的访问令牌时,TokenManager 将返回相同的 CompletableFuture,因为请求尚未完成。所以 req2 不会检测到访问令牌已经被刷新,但它会被阻塞(它的线程),直到获得刷新的令牌。

有关关于android:何时用刷新令牌交换访问令牌的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  3. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  4. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  5. ruby-on-rails - Sphinx - 何时对字段使用 'has' 和 'indexes' - 2

    我几天前在我的ruby​​onrails2.3.2上安装了Sphinx和Thinking-Sphinx,基本搜索效果很好。这意味着,没有任何条件。现在,我想用一些条件过滤搜索。我有公告模型,索引如下所示:define_indexdoindexestitle,:as=>:title,:sortable=>trueindexesdescription,:as=>:description,:sortable=>trueend也许我错了,但我注意到只有当我将:sortable=>true语法添加到这些属性时,我才能将它们用作搜索条件。否则它找不到任何东西。现在,我还在使用acts_as_tag

  6. ruby - 有没有办法从 ruby​​ case 语句中访问表达式? - 2

    我想从then子句中访问c​​ase语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案

  7. ruby - 从外部访问类的实例变量 - 2

    我理解(我认为)Ruby中类变量和类的实例变量之间的区别。我想知道如何从该类外部访问该类的实例变量。从内部(即在类方法中而不是实例方法中),它可以直接访问,但是从外部,有没有办法做MyClass.class.[@$#]variablename?我没有任何具体原因要这样做,只是学习Ruby并想知道是否可行。 最佳答案 classMyClass@my_class_instance_var="foo"class上述yield:>>foo我相信Arkku演示了如何从类外部访问类变量(@@),而不是类实例变量(@)。我从这篇文章中提取了上述内

  8. ruby-on-rails - 使用 HTTP.get_response 检索 Facebook 访问 token 时出现 Rails EOF 错误 - 2

    我试图在我的网站上实现使用Facebook登录功能,但在尝试从Facebook取回访问token时遇到障碍。这是我的代码:ifparams[:error_reason]=="user_denied"thenflash[:error]="TologinwithFacebook,youmustclick'Allow'toletthesiteaccessyourinformation"redirect_to:loginelsifparams[:code]thentoken_uri=URI.parse("https://graph.facebook.com/oauth/access_token

  9. ruby-on-rails - 关于 Ruby 的一般问题 - 2

    我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia

  10. ruby - 使用 Class.new 时访问外部范围 - 2

    是否有可能以某种方式访问​​Class.new范围内的a?a=5Class.new{defb;aend}.new.b#NameError:undefinedlocalvariableormethod`a'for#:0x007fa8b15e9af0>#:in`b' 最佳答案 即使@MarekLipka的回答是正确的——改变变量范围总是有风险的。这是可行的,因为每个block都带有创建它的上下文,因此您的局部变量a突然变得不那么局部了——它变成了一个“隐藏的”全局变量:a=5object=Class.new{define_method(

随机推荐