在行动中更新IsAuthenticated并不适用于后续操作?

时间:2014-03-12 23:42:12

标签: asp.net-mvc-4 authentication

我做了这个动作:

public ActionResult Index(string username, int userID)
{
  if (!HttpContext.User.Identity.IsAuthenticated)
  {
    var ticket = new FormsAuthenticationTicket(2, username, DateTime.Now, DateTime.Now.AddDays(7), false, string.Empty);
    var encr = FormsAuthentication.Encrypt(ticket);
    var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encr);
    Response.Cookies.Add(cookie);
  }
  return View("Index",null,username);
}  

稍后,将调用此部分视图操作:

public PartialViewResult PageHeader()
{
  if (HttpContext.User.Identity.IsAuthenticated)
  {
     string username = HttpContext.User.Identity.Name;
     ...  
  }
}

即使在上一个操作中设置了auth cookie,表达式HttpContext.User.Identity.IsAuthenticated也会被评估为false。只有在刷新页面后,表达式才会评估为真 所以我的问题是:如何告诉asp.net mvc用户已经过身份验证,并使用HttpContext.User.Identity属性?

2 个答案:

答案 0 :(得分:2)

ASP.NET 在请求开头只设置一次 HttpContext.User.Identity.IsAuthenticated

因此,稍后设置控制器操作中的身份验证Cookie对HttpContext.User.Identity.IsAuthenticated没有任何影响,因为您处于同一请求的上下文中。

建议的"工作流程"表单身份验证的内容如下:

  • 客户端向服务器发送用户名和密码
  • 服务器验证凭据并设置身份验证cookie
  • 客户端客户端在后续请求
  • 上发送身份验证Cookie

因此,您需要发出新请求才能正确更新HttpContext.User.Identity.IsAuthenticated

成功登录的标准做法是将客户端重定向到原始网址,或者在您的情况下将其重定向到同一操作:

public ActionResult Index(string username, int userID)
{
    if (!HttpContext.User.Identity.IsAuthenticated)
    {
        var ticket = new FormsAuthenticationTicket(2, username, DateTime.Now, 
            DateTime.Now.AddDays(7), false, string.Empty);
        var encr = FormsAuthentication.Encrypt(ticket);
        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encr);
        Response.Cookies.Add(cookie);
        return RedirectToAction("Index", new {username, userID});
    }
    return View("Index", null, username);
}   

答案 1 :(得分:2)

这似乎是一种奇怪的做法;您在错误的图层中执行身份验证。

用户通常在之前通过身份验证进入操作方法(被调用)。这样,如果未经过身份验证,您可以阻止它们进入控制器或操作。

为什么不使用框架来处理这个任务?它将在管道中的正确阶段自动为您设置cookie。

Subclass MembershipProvider和Override ValidateUser(string username, string password)

在此方法中,使用用户名和密码进行验证。如果验证失败(用户名/密码错误等),return false。如果成功,return true,将为您设置身份验证cookie。

从这一点开始,您可以创建授权属性(通过继承 AuthorizationAttribute )并装饰您的控制器或操作。在这些属性中,您可以执行诸如检查用户角色,范围,权限等操作,并在用户未正确授权发出请求时拒绝该请求。这非常简单。

您需要做三件事:

  • 创建自定义 MembershipProvider ,验证用户(用户名/密码检查),
  • 创建自定义 AuthorizeAttribute ,用于检查用户的身份验证/授权状态。它可以像验证它们已经过身份验证一样简单(只需返回User.Identity.IsAuthenticated。如果它false,它会将它们发送到登录屏幕。否则,它将允许他们继续请求),并将自定义提供程序添加到 web.config ,以便它知道使用它。如果您还没有这样做,可能还需要在web.config中设置“登录”页面。

这是正确的(呃)方式,可能会解决您的问题,同时还可以清理您的项目。

// The provider
// This is what gets called during login. your logic to validate the user is placed here
// Return true or false which will indicate whether or not an auth token/cookie will be set
 public class MyCustomProvider : MembershipProvider
 {
    public override bool ValidateUser(string username, string password)
    {
        const string testUsername = "User1";
        const string testPassword = "abcd1234";

        // do whatever you need to do in order to verify this dude's identity
        return username.Equals(testUsername) && password.Equals(testPassword);
    }
    //... bunch of other overrides. I only implement them if I actually use them otherwise just wrap them in a region and hide them.
 }

// The web.config update. Tell the framework where your login page is.  Typically, in an MVC project,
// The view is in Views/Account and the action Login on the Account controller calls WebSecurity.Login
// which is what runs your provider. Define both here.

 <system.web>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/Login" />
    </authentication>
    <membership defaultProvider="MyCustomProvider">
      <providers>
        <remove name="AspNetSqlProvider" />
        <add name="MyCustomProvider"
           type="FullyQualifiedName.MyCustomProvider, AuthDemo, Version=1.0.0.0, Culture=neutral" />
      </providers>
    </membership>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>


// The authorize attribute
// This is where you can check your user's authorization. In this example, I just
// check to see that he was authenticated by the provider.
public class MyCustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        // do whatever you need to do here to verify that this dude is allowed to be here
        return httpContext.User.Identity.IsAuthenticated;
    }
}

// sample usage of the attribute
// the framework will run this attribute before it allows the user into the controller.
// You could also do this at the action level instead of the controller level
[MyCustomAuthorize]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult About()
    {
        ViewBag.Message = "Your application description page.";

        return View();
    }

    public ActionResult Contact()
    {
        ViewBag.Message = "Your contact page.";

        return View();
    }
}