开发者

Quick-start for ASP.NET MVC security

开发者 https://www.devze.com 2023-02-08 13:32 出处:网络
MVC newbie question: I\'ve got my project up & running, and all working fine.Now I want to start restricting access to certain views - and even whole controllers.I know that the VS 2010 package co

MVC newbie question: I've got my project up & running, and all working fine. Now I want to start restricting access to certain views - and even whole controllers. I know that the VS 2010 package comes with a standard, built-in security module, including a little shrink-wrapped database that stores your usernames and passwords for you, lest - Heaven forfend! - you use a non-standard approach.

Well, I don't want to use the built-in security. I've got my own user tables, and I know how to encrypt the passwords myself, thank you very much. All I want to do is have a login method, and if I determine that the login was successful, then I want to set the session as authenticated, and allow the user to access the restricted views. Shouldn't be too difficult, right?

I've Googled for MVC security; the problem is not lack of information, but rather too 开发者_开发技巧much of it... so if anyone can just cut through my personal OutOfMemoryException and give me a "Quick Start" applicable to my situation, I'd really appreciate it...


One of the nice things about ASP.NET is that it is very extensible. Yes, the default model for authentication and authorization is to use the ASP.NET provided membership tables (either in a separate database or added to your own). Luckily, there is a way around that.

The easiest (and proper) way to achieve what you're looking to do is to create a custom MembershipProvider that uses your existing database. Doing so will allow you to plug your custom authentication logic into the existing ASP.NET MVC authorization framework which means you can still control access to your Actions via attributes in your Controllers:

MSDN - Implementing a Membership Provider


I'd suggest you should use the FormsAuthenticationService to sign users in once you are satisfied they are in fact who they say they are.

The boilerplate MVC3 internet application project template gives some guidence on this (replace their membership code with your membership code).

If you want to restrict access to code, you could use CodeAccessSecurity and Permission attributes - these can be applied at class and method level. eg

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

And of course you can use web.config files to set permissions to areas of your web site.


Try this code as a guide we use this to log poeple in and out using our own model and database. The IdentitySession class can be used in controllers to get the signed in user data. I have tried to simplify our code a bit by cutting some out here so please don't expect this to just run. Hope it helps.

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号