在MVC应用程序中重新验证用户的操作

时间:2013-09-25 00:26:19

标签: asp.net-mvc asp.net-mvc-4 authentication windows-authentication

如何在MVC中执行Action之前强制用户重新进行身份验证?

我们正在使用Windows身份验证。我们希望确保某些操作由用户执行(如果用户忘记锁定其工作站,则阻止其他用户执行这些操作)。

理想情况下,我只能编写一个扩展Authorize的属性:

namespace AuthTest.Controllers
{
    [Authorize(Roles="MyApp")]
    public class HomeController : Controller
    {    
        public ActionResult Index()
        {
             // A regular action
            return View();
        } 

        [ReAuthenticate]
        public ActionResult CriticalAction()
        {
            // Do something important
            return View();
        }
     }
}

我似乎可以强制用户通过自定义ReAuthenticate属性在HTTP 401方法中发出AuthorizeCore响应来重新输入其凭据。但是,这需要一些技巧,因为Html.ActionLink发送了两个请求:

protected override bool AuthorizeCore(HttpContextBase httpContext)
{
    bool ok = base.AuthorizeCore(httpContext);
    if (!ok) return false;

    if (httpContext.Session["ReAuthCnt"] == null)
    {
        httpContext.Session["ReAuthCnt"] = 1;
        return false;
    }
    else if ((int) httpContext.Session["ReAuthCnt"] < 2)
    {
        httpContext.Session["ReAuthCnt"] = (int)httpContext.Session["ReAuthCnt"] + 1;
        return false;
    }
    else
    {
        httpContext.Session["ReAuthCnt"]  = 0;
        return true;
    }
}

有没有更好的方法来完成重新授权?

4 个答案:

答案 0 :(得分:0)

如果用户正在执行POST,您是否可以向该表单添加用户名和密码字段,然后在控制器中或使用ActionFilter验证Active Directory的凭据?

答案 1 :(得分:0)

如果企业允许您实际使用表单来重新验证它们(换句话说有一个页面,他们输入用户名和密码),那么您可以执行以下操作。

ReauthorizeAttribute

// custom page where user does type user/pass
private string revalidateLoginUrl = "/account/reauth";
private bool? hasReauthenticated = false;

protected override bool AuthorizeCore(HttpContextBase httpContext)
{
  var authUrl = HttpContext.Request.Url;
  hasReauthenticated = httpContext.Session[authUrl] as bool?

  // could be just (hasReauthenticated)
  // this look a bit more readable
  return (hasReauthenticated == true);
}

public override void OnAuthorization(AuthorizationContext filterContext) 
{
  if (filterContext == null) 
  {
    throw new ArgumentNullException("filterContext");
  }

  var isAuthorized = AuthorizeCore(filterContext.HttpContext);

  var authUrl = filterContext.HttpContext.Request.Url;
  filterContext.HttpContext.Session[authUrl] = false;

  if (!isAuthorized) 
  {
    HandleUnauthorizedRequest(filterContext);
  }
}

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
  // something like this
  var fullUrl = validateLoginurl + "?returnUrl=" 
    + HttpUtility.UrlEncode(revalidaetLoginUrl);

  filterContext.HttpContext.Response.Redirect(validateLoginUrl);
}

ReauthModel

public class ReauthModel
{
  public string Username { get; set; }
  public string Password { get; set; }
  public string ReturnUrl { get; set; }
}

AccoountController.cs (Validate a username and password against Active Directory?

using System.DirectoryServices.AccountManagement;

public ActionResult Reauth(string returnUrl)
{
  var model = new ReauthModel();
  model.ReturnUrl = returnUrl;

  return View(model);
}

[ValidateAntiForgeryToken]
public ActionResult Reauth(ReauthModel model)
{
  using(PrincipalContext pc = new 
    PrincipalContext(ContextType.Domain, "YOURDOMAIN"))
  {
    // validate the credentials
    bool isValid = pc.ValidateCredentials("myuser", "mypassword");
    if (isValid)
    {
      Session[model.ReturnUrl] = true;
      return RedirectTolocal(model.ReturnUrl);
    }
  }

  // not authenticated
  return RedirectToAction("?");

  //or
  model.Username = string.Empty;
  model.Passsword = string.Empty;

  return View(model);
}

我认为您可以根据ReauthModel想象视图的外观。

注意:除了您使用的任何其他authorizeattribute之外,还应该使用,而不是。由于用户在网站上输入用户名和密码,因此需要才能使用SSL(即使它是内部的)。

答案 2 :(得分:0)

我会以不同的方式接近这一点。这听起来像你真正想要的是临时凭证提升,类似于UAC或Sudo,但在您的网站上。您可能希望如果经过一定时间后用户必须再次输入凭据才能访问这些功能。

我将采用的方法是创建一个自定义IPrincipal,允许您临时向用户添加特定角色,并在一段时间后使该角色失效。这不会与存储在数据库中的用户分配的角色相关联,除了可能说只有具有特定角色的用户才能被提升。

这样,您只需执行密码检查,将角色临时添加到用户角色列表,然后标准的授权属性就会允许它们进入。

答案 3 :(得分:-2)

你可以从这里得到想法我在这里做角色基础授权

[Authorize(Roles = "admin,superadmin")]//Controler Authorization
        public class ControlController : Controller
        {

            [Authorize(Roles = "superadmin")]//action Authorization
            public ActionResult youraction()
            {
                return View();
            }
      }