5

更新:

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

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

两个应用程序都在同一个域上。


更新:我们是否应该在 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);
}

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;
    }
}
4

2 回答 2

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属性上。这适用于 MVCControllerApiControllers。

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

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

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

你应该尽量避免通过这样做来获得它们:

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

您可以像这样从 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;
    }
}

更新

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

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

更新

根据谁有权查看您的 web.config 文件,可能存在安全问题。如果您像这样将其签入您的源代码控制存储库,任何可以访问您的源代码的人都可以看到验证和加密密钥。

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

另一种选择是将它们排除在源代码控制之外,但是每次部署时都必须手动更新 web.config。

于 2013-04-23T12:41:10.950 回答
0

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

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

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 应用程序。

于 2013-04-23T13:17:43.407 回答