4

我有一个使用自定义身份验证机制的带有 OData V4 服务的 WebAPI 2.2。基本上,它类似于 OAuth 的 Bearer 身份验证,即使用用户名和密码向特定端点发出请求并返回令牌。然后,该令牌将包含在所有后续请求的 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 标头响应,并且已为基本身份验证指定凭据另一个请求将使用所需的身份验证标头自动发送)但没有运气。

任何帮助/建议将不胜感激。

4

2 回答 2

1

解决方案位于AuthenticaionManager类中。通过通过其Register方法注册您自己的IAuthenticationModule实现,您将能够做您正在寻找的事情。

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

到目前为止,我发现处理过期令牌的唯一方法是在从授权服务器获取令牌的同时存储过期时间,并在它接近过期时刷新它。“关闭”是指它是否会在 n 秒内过期。我更喜欢这个阈值作为我检索令牌的网络超时。如果它已过期甚至即将过期,我将从服务器获得一个新令牌,甚至无需尝试最后一个令牌。在本节中随意使用您喜欢的任何测量值。;) 但是没有办法多次响应您的授权服务器的挑战,它不会永远挑战您。

这里查看有关上述类和接口的示例。

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

于 2016-03-06T11:16:18.417 回答
0

也许您忘记在 GetData 中挂钩 context_ReceivingResponse?(我没有看到)否则在发送和接收事件中记录 http-headers 以确保。

于 2015-09-01T08:07:08.490 回答