我正在使用REST API,如果我的授权令牌已过期,则返回401。当我收到401时,我想运行我的身份验证逻辑,检索一个新令牌,然后重试我的原始呼叫。什么是最好的方法。
现在,我有一个Authenticator类,“知道”如何使用API进行身份验证。其余的数据访问逻辑存在于Repository对象中。 Repository对象负责使用Authenticator中存储的信息向API发送请求以检索信息。
这方面的一个例子是Repository.List()[它不是真正的静态,只是为了简洁起见这样写)。从概念上讲,这就是List()应该做的事情。
这个模式将用于我所有存储库中的所有方法,所以我想要一个委托或者我可以用于所有API调用的东西。
有什么想法吗?
谢谢, 格雷格
答案 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时重新进行身份验证。否则,它将成功或抛出我可以处理的异常。