OData V4客户端代码生成器并处理401响应

本文关键字:处理 响应 代码生成器 V4 客户端 OData | 更新日期: 2023-09-27 18:02:50

我有一个使用自定义身份验证机制的WebAPI 2.2 w/OData V4服务。基本上,它类似于OAuth的承载身份验证,即使用用户名和密码向特定端点发出请求,并返回令牌。然后将令牌包含在所有后续请求的Authorization头中。我正在使用OData V4客户端代码生成器(2.3.0),并使用DataServiceContext的BuildingRequest事件手动添加授权头,如下所示…

private void GetData() {
    var context = new DataAccess.Default.Container(new Uri("http://myserver/API/"));
    context.BuildingRequest += onBuildingRequest;
    var data = context.Computers.ToList();
}
void onBuildingRequest(object sender, Microsoft.OData.Client.BuildingRequestEventArgs e)
{
    if (_token == null)
        _token = GetToken();
    e.Headers.Add("Authorization", "MyToken " + _token);
}

我遇到的问题是令牌在一定时间后过期,所以过了一会儿我将开始获得401响应,这会导致在上下文中的IQueryables调用它们的GetEnumerator(上面代码中的ToList调用)时抛出异常。我可以包住每一个我枚举端点的地方但那不是很理想。我发现我可以在DataServiceContext的ReceivingResponse事件中检测到401,并标记令牌已经过期,但是这并不能阻止调用失败,它只会使后续调用工作。

void context_ReceivingResponse(object sender, ReceivingResponseEventArgs e)
{
    if (e.ResponseMessage.StatusCode == 401)
    {
        _token = null;
    }
}

所以在这一点上,我试图找出一种方法来处理401,而不需要每次调用(这通常是在枚举IQueryable时)都包装在try/catch中。我试图找出一种方法,让web请求处理我的自定义身份验证的方式类似于它如何处理基本身份验证(如果服务器响应与401和WWW-Authenticate头,并已为基本身份验证指定了一个凭据,另一个请求将自动发送所需的身份验证头),但没有运气。

OData V4客户端代码生成器并处理401响应

解决方案在authenticationmanager类中。通过注册IAuthenticationModule的Register方法,你就可以做你想做的事情了。

你可能还需要另一个类来实现icredential和处理你的身份验证参数,比如你的令牌端点url等,然后将它传递给你的DataServiceContext。您甚至可以使用它来缓存您的最后一个令牌及其过期时间。

到目前为止,我发现处理过期令牌的唯一方法是在从授权服务器获取令牌时存储过期时间,并在接近过期时刷新它。这里的"close"我的意思是如果它将在n秒内过期。我倾向于将此阈值作为检索令牌的网络超时。如果它已经过期或接近过期,我将从服务器获得一个新的令牌,甚至没有尝试最后一个。请随意在本节中使用您喜欢的任何度量。,)但是没有办法多次响应您的授权服务器的挑战,它也不会永远挑战您。

请看这里的一个关于上述类和接口的例子。

顺便说一句,在可移植类库中使用它,你可能有点不走运。pcl中没有authenticationmanager和IAuthenticationModule的标志。使用某种抽象可能会有所帮助。

也许你忘了在GetData中hook context_ReceivingResponse ?(我看不出来)否则,记录发送和接收事件中的http报头以确保。