WebAPI + Forms Authentication + SimpleMembershipProvider使用WindowsIdentity时不应该使用

时间:2013-04-14 01:41:28

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

我做了什么

我正在构建一个REST-ish WebAPI应用程序。我正在尝试在此处实现表单身份验证,因此客户端可以允许用户从其浏览器登录/注册/注销。我正在使用simpleMembership,用户存储在我的应用程序的simpleMembership数据库表中。作为第一步,我在AccountsController中实现了一个登录方法:

    [System.Web.Http.HttpPost]
    public HttpResponseMessage LogIn(LoginModel model)
    {
        if (ModelState.IsValid)
        {
            if (User.Identity.IsAuthenticated)
            {
                return Request.CreateResponse(HttpStatusCode.Conflict, "already logged in.");
            }
            if (WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
            {
                FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                //TODO: look up by id, not by name
                var userProfile = _service.GetUser(WebSecurity.GetUserId(model.UserName));
                return Request.CreateResponse(HttpStatusCode.OK, userProfile);
            }
            else
            {
                return new HttpResponseMessage(HttpStatusCode.Unauthorized);
            }
        }

        // If we got this far, something failed
        return new HttpResponseMessage(HttpStatusCode.InternalServerError);
    }

问题

以下是发生的事情:

  1. 我在if (User.Identity.IsAuthenticated)设置断点。
  2. 使用POSTMan或Fiddler之类的东西,我尝试使用一些伪造的凭据登录。
  3. 我按照预期点击断点并为IsAuthenticated获得“False”。
  4. 我跳到下一个'if',尝试LogIn失败,正如预期的那样。
  5. else语句中的代码被命中,但一旦返回,1)我的断点再次被击中,2)主体被设置为我的Windows身份。两者都是意料之外的,我正在试图弄清楚如何纠正它。
  6. enter image description here

    预期行为

    • 该方法只返回401 Unauthorized,因为我的应用程序数据库中不存在虚假用户。

    配置

    认为这是一个配置问题 - 由于某种原因,在身份验证失败时,主体会自动设置为我的Windows帐户。一些与我的配置相关的细节:

    <authentication mode="Forms">
      <forms loginUrl="~/" timeout="2880" />
    </authentication>
    
    • 我没有在应用程序的任何位置启用Windows身份验证。我的web.config在^
    • 之上
    • 使用IISManager我已禁用匿名身份验证
    • 在我的applicationhost.config中,我已禁用Windows和匿名身份验证

    问题

    1. 为什么断点被击中两次,而不是只返回未授权的LogIn方法,因为最后一个“else”被击中?
    2. 为什么我的Windows凭据被用于此意外和不受欢迎的“环回”?
    3. 如何防止这种情况发生?或者:
    4. 我是否需要使用MessageHandler来设置主体?如果是这样,这会如何影响[Authenticate]和IsAuthenticated?有什么例子吗?
    5. 更新1

      我已经尝试注册以下处理程序:

      public class PrincipalHandler : DelegatingHandler
          {
      
              protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
                                                                                     System.Threading.CancellationToken
                                                                                         cancellationToken)
              {
                  HttpContext.Current.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
                  Thread.CurrentPrincipal = HttpContext.Current.User;
                  return await base.SendAsync(request, cancellationToken);
              }
      
          }
      

      现在,主体永远不会设置为我的Windows身份。从POSTMan(浏览器扩展),if语句被命中两次,我得到一个弹出窗口,要求提供凭据。来自Fiddler,我按照预期获得了401 Unauthorized。

      新问题

      1. 如何根据响应cookie中的内容设置主体,并根据我的应用程序的简单成员资格表进行身份验证?
      2. 更新2

        这篇文章似乎让我朝着正确的方向发展 - 在我的LoginMethod中使用Membership而不是User:

        ASP.NET MVC - Set custom IIdentity or IPrincipal

        将继续更新进度,但我仍然愿意接受建议/推荐。

        更新3 我从未如此放松和生气 - 这里不需要自定义处理程序。我的项目属性中启用了Windows身份验证。登录和注销的工作解决方案在这里,并且“正常工作”我的会员表:

        public HttpResponseMessage LogIn(LoginModel model)
                {
                    if (ModelState.IsValid)
                    {
                        if (User.Identity.IsAuthenticated)
                        {
                            return Request.CreateResponse(HttpStatusCode.Conflict, "already logged in.");
                        }
                        if (WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
                        {
                            FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                            return Request.CreateResponse(HttpStatusCode.OK, "logged in successfully");
                        }
                        else
                        {
                            return new HttpResponseMessage(HttpStatusCode.Unauthorized);
                        }
                    }
        
                    // If we got this far, something failed
                    return new HttpResponseMessage(HttpStatusCode.InternalServerError);
                }
        
        public HttpResponseMessage LogOut()
                {
                    if (User.Identity.IsAuthenticated)
                    {
                        WebSecurity.Logout();
                        return Request.CreateResponse(HttpStatusCode.OK, "logged out successfully.");
                    }
                    return Request.CreateResponse(HttpStatusCode.Conflict, "already done.");
                }
        

1 个答案:

答案 0 :(得分:4)

您使用IIS Express进行开发吗?如果是这样,请在Visual Studio中单击您的项目并检查属性窗口。这里有一个Windows身份验证选项,我认为默认情况下启用。在这里也禁用它。