17

我有一个具有 Ownin cookie 身份验证的 Mvc 5 客户端。我还有一个受 Owin Bearer 令牌保护的 Web Api(我使用了创建令牌端点的 VS2013 Web Api 模板)

好的,现在我的 Mvc 5 客户端需要使用我的 WebApi。我创建了一个获取不记名令牌的方法:

internal async Task<string> GetBearerToken(string siteUrl, string Username, string Password)
{
     HttpClient client = new HttpClient();

     client.BaseAddress = new Uri(siteUrl);
     client.DefaultRequestHeaders.Accept.Clear();

     HttpContent requestContent = new StringContent("grant_type=password&username=" + Username + "&password=" + Password, Encoding.UTF8, "application/x-www-form-urlencoded");

     HttpResponseMessage responseMessage = await client.PostAsync("Token", requestContent);

     if (responseMessage.IsSuccessStatusCode)
     {
         TokenResponseModel response = await responseMessage.Content.ReadAsAsync<TokenResponseModel>();
         return response.AccessToken;
     }

     return "";
}

在我的 Mvc 动作中,我称之为:

public async Task<ActionResult> Index()
{
     var token = await GetBearerToken("http://localhost:6144/", "teste", "123456");

     using (var client = new HttpClient())
     {
         client.DefaultRequestHeaders.Add("Authorization", "Bearer "+ token);

         var response = await client.GetAsync("http://localhost:6144/api/values");

         if (response.IsSuccessStatusCode)
         {
             var data = response.Content.ReadAsAsync<IEnumerable<string>>();

             return Json(data.Result, JsonRequestBehavior.AllowGet);
         }
     }   
}

这一切都很好......但是我需要在我的所有操作中使用Web Api......那么我怎样才能保留那个令牌(尽管每个请求都会获得一个新令牌)以及如何验证它是否过期......有可能以某种方式将其与身份验证cookie保持在一起?处理这种情况的任何最佳做法?

谢谢

4

3 回答 3

16

如果我做对了,您的 MVC 5 客户端应用程序正在访问不同应用程序的 WebAPI。MVC 5 客户端使用 cookie 对用户进行身份验证。要访问 WebAPI,您可以从 /Token 端点获取 Bearer 令牌,并将其发送到 Authorization 标头中。

您无需从客户端 Javascript 代码调用 WebAPI,只需从运行在 MVC5 应用程序服务器上的 MVC 操作中调用它。

在每次服务调用之前获取新令牌听起来是错误的。这意味着每次 2 次往返。这不可能是高性能的。

如果我没看错,你可以:

  1. 将令牌存储在 Session 对象中。只要您的 MVC 应用程序用户通过身份验证并且他的会话处于活动状态,那么您将始终拥有相同的令牌。如果它已过期,您将从 WebAPI 获得 401 未经授权的访问。为了使您的 MVC 操作单元可测试,您可以将会话访问包装到您注入到操作中的服务中(依赖注入)。

  2. 您可以将令牌存储在类似于已经存在的身份验证 cookie 的 cookie 中。这样你就不需要服务器端的 Session 了。再次在这里,我将从 Cookie 获取令牌的访问权限包装在您的所有操作都使用的服务中。

我会使用会话存储。简单的。直线前进。但也许我错过了什么

希望这对您有所帮助。反馈赞赏:-)

于 2014-03-29T20:30:26.327 回答
4

不记名令牌不是授权 Web 应用程序的好方法。如果您将服务的令牌存储在 cookie 中,它将可供应用程序的客户端使用,因此服务层将容易受到应用程序客户端的攻击。唯一的解决方案似乎是在会话中保留令牌,但您将失去应用程序的无状态特性。

这里描述了应该使用什么/如何使用不记名令牌: “不记名令牌只是一个大的随机字符串,客户端必须在每次 API 调用时提供。不记名令牌很简单,因为两端都不需要特殊的签名或验证码。客户端负责将令牌存储在安全的地方并随每个请求发送。服务器负责在数据库中查找令牌并确保它是有效的——就是这样。”。

这是在客户端直接与服务对话的单页应用程序中使用不记名令牌的好例子。

无论如何,我建议您使用HMAC 身份验证、BCrypt 或 ClientCertificates。甚至亚马逊也使用它来验证 REST 请求。

于 2014-03-29T20:33:13.587 回答
2

如果您想管理所有操作中的令牌,您应该更改代码以使用自定义授权过滤器。该过滤器可以添加到所有 Web API 请求、控制器的所有操作或单个操作。为此,从 AuthorizeAttribute 派生并从过滤器发出 GetBearerToken 调用。将令牌粘贴到 HTTP 上下文中,以便在请求处理期间使用。您可以使用工厂生成它们并添加适当的令牌进行身份验证,而不是直接调用创建 HttpClient 实例。

至于确定令牌是否过期,您可以添加一个额外的过滤器来检查返回的特定错误,或者在授权过滤器中发出检查。我不知道您的所有要求,因此很难在那里确定合适的解决方案。

于 2014-03-26T17:55:10.043 回答