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

use*_*004 5 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>
Run Code Online (Sandbox Code Playgroud)

两个应用程序都在同一个域中.


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


目前,我有一个MVC项目,它使用表单身份验证和WebAPI项目.问题是我无法在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);
}
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

dan*_*wig 9

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

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

    // set redirect
}
Run Code Online (Sandbox Code Playgroud)

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

<authentication mode="Forms">
    <forms timeout="15" />
</authentication>
Run Code Online (Sandbox Code Playgroud)

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

此外,如果您的MVC应用程序和WebAPI应用程序托管在Web服务器(或不同服务器)上的不同节点上,则MVC项目和WebAPI项目machineKey在其web.config文件中必须具有相同的内容.他们还必须在同一个域,但如果是有独立的web.config文件中单独的应用程序,它们必须具有相同的machineKey值(decryption,decryptionKey,validationvalidationKey).这些是验证,加密和解密.ASPXAUTH cookie所需的值.

我们甚至应该在WebAPI中使用cookie吗?

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

您应该尝试避免的是通过执行以下操作来获取它们:

HttpCookie authCookie = HttpContext.Current.Request.Cookies["name"];
Run Code Online (Sandbox Code Playgroud)

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

更新

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

只需单击"生成密钥"按钮,然后将生成的<machineKey ../>部分粘贴到<system.web>两个web.config文件的部分下.

更新

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

我所做的是有点复杂,但它保持这些字符串安全.您可以改为存储validationKeyencryptionKeyappSettings,然后加密appSettings配置文件的各个部分(使用类似CloudConfigCrypto的东西).这意味着无法访问加密证书私钥的任何人都无法读取这些值.然后,您可以在运行期间使用Microsoft.Web.Administration.ServerManager该类更改machineKeyApplication_Start.但是,关于这个的更多细节超出了这个问题的范围.

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