如何使用Web服务重新进行身份验证,然后重试REST调用

时间:2012-01-27 21:04:49

标签: c#

我正在使用REST API,如果我的授权令牌已过期,则返回401。当我收到401时,我想运行我的身份验证逻辑,检索一个新令牌,然后重试我的原始呼叫。什么是最好的方法。

现在,我有一个Authenticator类,“知道”如何使用API​​进行身份验证。其余的数据访问逻辑存在于Repository对象中。 Repository对象负责使用Authenticator中存储的信息向API发送请求以检索信息。

这方面的一个例子是Repository.List()[它不是真正的静态,只是为了简洁起见这样写)。从概念上讲,这就是List()应该做的事情。

  • 尝试连接API并获取项目列表
  • 如果401错误,请重新进行身份验证并重试
  • 返回项目列表或抛出异常

这个模式将用于我所有存储库中的所有方法,所以我想要一个委托或者我可以用于所有API调用的东西。

有什么想法吗?

谢谢, 格雷格

1 个答案:

答案 0 :(得分:1)

我想出了一个运行良好的解决方案。

我创建了一个静态方法,接受两个参数,一个Func和一个对我的引用 验证对象。 Authentication对象可以重新进行身份验证,并保存用于进行API调用的身份验证信息。我使用了一个ref,因为我不想为一个存在不同身份验证令牌的帐户使用Authenticator的多个实例,但我需要能够同时支持多个帐户,所以我无法使其成为静态。

public static string ReauthenticateOn401(
    Func<Authenticator, string> method, 
    ref Authenticator authenticator)
{
    if (method == null)
        throw new ArgumentNullException("action");

    if (authenticator == null)
        throw new ArgumentNullException("authenticator");

    int attempts_remaining = 2;
    bool reauth_attempted = false;
    while (attempts_remaining > 0)
    {
        try
        {
            return method(authenticator);
        }
        catch (WebException e)
        {
            if (e.Response != null && reauth_attempted == false)
            {
                if (((HttpWebResponse)e.Response).StatusCode == HttpStatusCode.Unauthorized)
                {
                    authenticator.GetAuthToken();
                    reauth_attempted = true;
                    attempts_remaining--;
                }
                else
                {
                    throw;
                }
            }
            else
            {
                throw;
            }
        }
    }
    throw new Exception("The ReauthenticateOn401 method failed to return a response or catch/throw an exception.  The log flowed outside the while loop (not expected to be possible) and is generating this generic exception");
        }

然后我有不同的类来从API请求数据。以下是其中一个可能的样子,当实例化类时,将_authenticator传递给类。

string json = Authenticator.ReauthenticateOn401( (authenticator) =>
{
    string apiUrl = "http:/blahblahblah.api.com"
    HttpWebRequest request = WebRequest.Create(apiUrl) as HttpWebRequest;
    //Add headers, or adjust the body as necessary for your API
    using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
    {
        return reader.ReadToEnd();
    }
}, ref _authenticator);

美丽的是,我可以传递我想要的任何逻辑ReathenticateOn401,并且它将尝试调用该方法,然后在收到401时重新进行身份验证。否则,它将成功或抛出我可以处理的异常。