ASP.NET MVC安全性的快速入门

时间:2011-02-03 13:24:16

标签: c# asp.net-mvc security

MVC新手问题:我的项目已经完成了跑步,一切正常。现在我想开始限制对某些视图的访问 - 甚至是整个控制器。我知道VS 2010软件包附带一个标准的内置安全模块,包括一个小的收缩包装数据库,可以存储你的用户名和密码,以免天堂冒犯! - 您使用非标准方法。

好吧,我不想使用内置安全性。我有自己的用户表,我知道如何自己加密密码,非常感谢。我想要做的就是使用登录方法,如果我确定登录成功,那么我想将会话设置为已通过身份验证,并允许用户访问受限制的视图。不应该太难,对吗?

我用Google搜索MVC安全性;问题不在于缺乏信息,而在于缺乏信息......所以如果有人能够切断我的个人OutOfMemoryException并给我一个适用于我的情况的“快速入门”,我真的很感激...

3 个答案:

答案 0 :(得分:4)

ASP.NET的一个好处是它非常易于扩展。是的,身份验证和授权的默认模型是使用ASP.NET提供的成员资格表(在单独的数据库中或添加到您自己的数据库中)。幸运的是,有一种解决方法。

实现您希望执行的操作的最简单(和正确)方法是创建使用现有数据库的自定义MembershipProvider。这样做将允许您将自定义身份验证逻辑插入现有的ASP.NET MVC授权框架,这意味着您仍然可以通过控制器中的属性控制对Actions的访问:

MSDN - Implementing a Membership Provider

答案 1 :(得分:1)

尝试使用此代码作为指南,我们使用此代码使用我们自己的模型和数据库来记录和退出。可以在控制器中使用IdentitySession类来获取已登录的用户数据。我试图通过在这里削减一些来简化我们的代码所以请不要指望这只是运行。希望它有所帮助。

public ActionResult Login(int pageId) {
  ViewData["ReturnUrl"] = Request["ReturnUrl"];
  return View(Cms3Configuration.DefaultViewModelWithPage(attachedPage));
}

public ActionResult Process(int pageId, string login, string password, string ReturnUrl) {
  var user = userRepository.GetByUserName(login);
  ViewData["ReturnUrl"] = ReturnUrl;
  if (user != null && authenticator.VerifyAccount(user, password)) {
    authenticator.SignIn(user);
    if (ReturnUrl.IsNotEmpty()) {
      return Redirect(ReturnUrl);
    }
    return Redirect("~" + attachedPage.Parent.Url);
  }
  ////login failed
  TempData[TempDataKeys.Error] = "Invalid login";
  return RedirectToAction("Login", new { pageId = pageId, ReturnUrl });
}

public ActionResult Logout(int pageId) {
  authenticator.SignOut();
  return RedirectToAction<LoginController>(x => x.Login(pageId), new {pageId = pageId});
}

public interface IAuthenticator {
  void SignIn(User person);
  IIdentity GetActiveIdentity();
  WindowsPrincipal GetActiveUser();
  void SignOut();
  bool VerifyAccount(User person, string password);
  bool HasRole(string person, string role);
}

public class Authenticator : IAuthenticator {
  private readonly IHttpContextProvider _httpContextProvider;
  private readonly ICryptographer _cryptographer;
  private readonly IRepository repository;

  public Authenticator(IHttpContextProvider httpContextProvider, ICryptographer cryptographer, IRepository repository) {
    _cryptographer = cryptographer;
    this.repository = repository;
    _httpContextProvider = httpContextProvider;
  }

  public void SignIn(User user) {
    FormsAuthentication.SignOut();
    if (user == null)
      return;
    DateTime issued = DateTime.Now;
    DateTime expires = issued.AddMinutes(30);
    if (user.ExpiryDate.HasValue) {
      if (user.Expires && expires > user.ExpiryDate)
        expires = (DateTime) user.ExpiryDate;
    }
    var roles = user.Roles.Select(x => x.Name).ToList();
    var ticket = new FormsAuthenticationTicket(1, user.UserName, issued, expires, false, string.Join(",", roles.Distinct().ToArray()));
    var encryptedTicket = FormsAuthentication.Encrypt(ticket);
    var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket) { Expires = ticket.Expiration };
    _httpContextProvider.GetCurrentHttpContext().Response.Cookies.Add(authCookie);
  }

  public IIdentity GetActiveIdentity() {
    var httpcontext = _httpContextProvider.GetCurrentHttpContext();
    if (httpcontext == null || httpcontext.User == null)
      return null;
    return httpcontext.User.Identity;
  }

  public WindowsPrincipal GetActiveUser() {
    return _httpContextProvider.GetCurrentHttpContext().User as WindowsPrincipal;
  }

  public void SignOut() {
    FormsAuthentication.SignOut();
  }

  public bool VerifyAccount(User person, string password) {
    string passwordHash = _cryptographer.HashPassword(password, person.PasswordSalt);
    return passwordHash == person.Password && !person.HasExpired() && person.Approved == true;
  }

}

public interface IIdentitySession<T> {
  T GetLoggedInIdentity();
  bool IsAuthenticated { get; }
  bool IsAdministrator { get; }
}

public class IdentitySession<T> : IIdentitySession<T> where T : Identity {
  private readonly IAuthenticator<T> authenticator;
  private readonly IRepository repository;
  private readonly IHttpContextProvider httpContextProvider;
  private T currentIdentity;
  private static readonly object _lock = new object();

  public IdentitySession(IAuthenticator<T> authenticator, IRepository repository,
                         IHttpContextProvider httpContextProvider) {
    this.authenticator = authenticator;
    this.activeDirectoryMapper = activeDirectoryMapper;
    this.repository = repository;
    this.httpContextProvider = httpContextProvider;
  }

  public virtual T GetLoggedInIdentity() {
    IIdentity identity = authenticator.GetActiveIdentity();

    if (identity == null)
      return null;

    if (!identity.IsAuthenticated) 
      return null;

    lock (_lock) {
      if (currentIdentity == null) {
        currentIdentity = repository.Query<T>().Where(x => x.UserName == identity.Name).FirstOrDefault();
      }
    }

    return currentIdentity;
  }

  public bool IsAuthenticated {
    get { return httpContextProvider.GetCurrentHttpContext().User.Identity.IsAuthenticated; }
  }

  public bool IsAdministrator {
    get { return false; }
  }
}

答案 2 :(得分:1)

我建议你应该使用FormsAuthenticationService在用户满意后对用户进行签名,他们实际上是他们所说的人。

样板MVC3互联网应用程序项目模板给出了一些指导(用你的会员代码替换他们的会员代码)。

如果要限制对代码的访问,可以使用CodeAccessSecurity和Permission属性 - 这些属性可以在类和方法级别应用。例如

[System.Security.Permissions.PrincipalPermission(SecurityAction.Demand, Authenticated = true, Role = "Admin")]
public ActionResult Index()
{
....
}

当然,您可以使用web.config文件为您的网站区域设置权限。