如何在并发环境中刷新访问令牌?

时间:2015-09-27 01:35:08

标签: elixir

任务是通过服务到服务身份验证机制查询其中一项Google服务,该机制假定每60分钟获取一个新的访问令牌。因此,如果请求失败,需要主动刷新或刷新。

最新似乎是一种防御性技术,不符合Elixir哲学。更多信息无法确定请求是否因访问令牌过期而失败,或者因为提供的凭据(电子邮件和密钥)通常无效 - 它将是相同的文本和相同的401代码。

也许有人可以就实施策略提出建议?这将是主机应用程序使用的库,并假设在令牌刷新期间(可能是90ms?)将创建新的请求,一般来说,等待新令牌而不是很快使用它们将是有益的。过时了。

1 个答案:

答案 0 :(得分:1)

通常,在Elixir / Erlang中,您有大约4种存储和使用共享数据的方法:

  1. GenServer或类似的 - 您实现了保存密钥并查询API的进程。您向它发送一条消息并返回数据。您不必担心数据来自何处,使用了哪些密钥以及如何使用。请求被序列化(并行完成),这可能是您不想要的。

  2. 代理 - 仅保存数据(密钥)。您调用Agent.get / 3并获取密钥。每当您发现密钥已过期时,您可以调用Agent.update / 3将新密钥放入代理。或者你总是打电话给update / 3.

  3. ETS表 - 最后的选择。如果你没有充分的理由,请不要使用它。

  4. 任何外部来源 - 您可以从磁盘,网络等读取。即使是最后的;)度假。

  5. 对于您的用例,第一个和第二个解决方案可能几乎相同。但是我会因为参数化而使用第二个。你可以这样写:

    defmodule TokenHolder do
    
      def start_link(user,passwd) do
        Agent.start_link(fn ->
          tok_time = get_token user, passwd
          {user,passwd,tok_time} 
        end, name: __MODULE__)
      end
    
      # refresh the token if older that one hour
      @max_age 60*60*1000000
    
      def token do
        Agent.get_and_update(__MODULE__, fn state={user,passwd,{token,retrieved}} ->
          now = :os.timestamp
          if(:timer.now_diff(now, retrieved) < @max_age) do
            # return old token and old state
            {token,state}
          else
            # retrieve new token, return it and return changed state
            tok_time = {token,_} = get_token user, passwd
            {token,{user,passwd,tok_time}}
          end
        end)
      end
    
      defp get_token(user,passwd) do
        token = ... # retrieve token somehow...
        {token,:os.timestamp}
      end
    
    end
    

    然后你就做了:

    {:ok,_} = TokenHolder.start_link("user","secret")
    token = TokenHolder.token