从Context / Cookie访问Web API中的用户数据

时间:2013-04-23 09:18:56

标签: asp.net-mvc asp.net-web-api

更新

我已将代码更改为FormsAuthentication.SetAuthCookie(_model.UserName, true);。我有2个Web.config文件,1个用于MVC,另一个用于WebAPI。在MVC配置中,我定义了

<authentication mode="Forms">
  <forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>

两个应用程序都位于同一个域中。


更新:我们是否应该在WebAPI中使用Cookie?


目前,我有一个使用表单身份验证和WebAPI项目的MVC项目。问题是我无法在WebAPI项目中获得与请求关联的用户。我认为这是可能的,或者实施可能是错误的?

注意:我将cookie代码放在WebAPI控制器方法中作为测试,它不在应有的位置。

MVC - 处理登录请求,创建身份验证票。

// POST: /Account/Login
[AllowAnonymous]
[HttpPost]
public ActionResult Login(LoginModel _model, string _returnUrl)
{
    if (ModelState.IsValid)
    {
        if (Membership.ValidateUser(_model.UserName, _model.Password))
        {
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(_model.UserName, true, 15);
            string encryptedTicket = FormsAuthentication.Encrypt(ticket);
            HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
            Response.Cookies.Add(cookie);

            // set redirect
        }
    }

    // If we got this far, something failed, redisplay form
    return View(_model);
}

WebAPI - 处理更新请求

[AcceptVerbs("PUT")]
public HttpResponseMessage UpdateInfo(int _id, ExampleModel _model)
{
    try
    {
        HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

        if (authCookie != null)
        {
            string encTicket = authCookie.Value;

            if (!String.IsNullOrEmpty(encTicket))
            {
                // decrypt the ticket if possible.
                FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(encTicket);

                var userData = ticket.UserData;
            }
        }

        // do update
        return Request.CreateResponse(HttpStatusCode.OK, data, GlobalConfiguration.Configuration);
    }
    catch (Exception err)
    {
        m_logger.Error(err);
        throw;
    }
}

2 个答案:

答案 0 :(得分:9)

为什么要手动创建表单身份验证票据呢?为什么你不能这样做?

if (Membership.ValidateUser(_model.UserName, _model.Password))
{
    FormsAuthentication.SetAuthCookie(_model.UserName, true);

    // set redirect
}

要控制超时,可以在web.config中设置:

<authentication mode="Forms">
    <forms timeout="15" />
</authentication>

如果您这样做,则不必检查cookie以获取用户名。它应该自动设置在控制器的User.Identity.Name属性上。这适用于MVC ControllerApiController s。

此外,如果您的MVC应用程序和WebAPI应用程序托管在Web服务器(或不同服务器)上的不同节点上,则MVC项目和WebAPI项目必须在其Web中具有相同的machineKey .config文件。它们也必须位于同一个域中,但如果它们是具有单独web.config文件的单独应用程序,则它们必须具有相同的machineKey值(decryptiondecryptionKey,{{1} }和validation)。这些是验证,加密和解密.ASPXAUTH cookie所需的值。

  

我们是否应该在WebAPI中使用Cookie?

如果您使用上述模式,则不必手动获取任何cookie,至少对于身份验证/授权。 Cookie是HTTP规范的一部分,还包括方法,标题,响应代码等.WebAPI将它们放在那里是有原因的。如果您需要它们,请使用它们。如果您不需要它们,请不要使用它们。

你应该尽量避免这样做:

validationKey

您可以从ApiController获取Cookie,如下所示:

HttpCookie authCookie = HttpContext.Current.Request.Cookies["name"];

<强>更新

我总是使用这个生成工具:http://aspnetresources.com/tools/machineKey

只需点击“生成密钥”按钮,然后将生成的IEnumerable<CookieHeaderValue> cookies = this.Request.Headers.GetCookies("name"); if (cookies.Any()) { IEnumerable<CookieState> cookie = cookies.First().Cookie; if (cookie.Any()) { string value = cookie.First().Value; } } 部分粘贴到两个web.config文件的<machineKey ../>部分下的某个位置。

<强>更新

可能存在安全问题,具体取决于谁有权查看您的web.config文件。如果您将其检查到源控制存储库中,那么任何可以访问源代码的人都可以看到验证和加密密钥。

我所做的事情有点令人费解,但它确保了这些字符串的安全性。您可以将<system.web>validationKey值存储在encryptionKey中,然后加密配置文件的appSettings部分(使用CloudConfigCrypto之类的内容)。这意味着无法访问加密证书私钥的任何人都无法读取这些值。然后,您可以在appSettings期间使用Microsoft.Web.Administration.ServerManager类在运行时更改machineKey值。关于这一点的更多细节不在这个问题的范围之内。

另一个选择是保持这些不受源代码控制,但是每次部署时都必须手动更新web.config。

答案 1 :(得分:0)

我找到了使用WebMatrix.WebData命名空间中的WebSecurity类将表单身份验证与Web API和MVC应用程序一起使用的最简单方法。它提供了对大多数常用操作的非常简单的访问,例如创建用户帐户,登录和注销用户,重置或更改密码。而且您不必自己处理会话cookie。

我在类似于你的设置中使用它,我们必须对Web API和MVC应用程序使用Forms身份验证。

API示例

登录:

if(WebSecurity.Login(username, password))
{
    return Request.CreateErrorResponse(
        HttpStatusCode.Forbidden, "Invalid credentials");
}
else
{
    return Request.CreateResponse(HttpStatusCode.OK);
}

寄存器:

if(WebSecurity.UserExists(username))
{
    return Request.CreateErrorResponse(
        HttpStatusCode.BadRequest, "Username already exists");
}

WebSecurity.CreateUserAndAccount(username, password, data);

HttpResponseMessage response = Request.CreateResponse(
    HttpStatusCode.Created, yourUserObject);
    response.Headers.Location = new Uri(
        Url.Link("DefaultApi",
            new { controller = "users", id = WebSecurity.GetUserId(username) }));
return response;

相同的调用适用于MVC应用程序。