static void

Forms Authentication

For .net 4.5+, see Owin

Web.config

<authentication mode="Forms">

    <forms loginUrl="Login.aspx"/>

</authentication>

<authorization>

    <deny users="?" />

</authorization>

In MVC, use a global action filter instead of <authorization>

In MVC, don't do the <location> sections, as it doesn't play well with routing.

ASP MVC

In ApplicationStart (App_Start/FilterConfig.cs) add a global Authorize action filter.

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new AuthorizeAttribute());
    }
}

Login page needs AllowAnonymous filters. For fun, this sets a custom cookie with roles.

[AllowAnonymous]
public ActionResult Login()
{
    var model = new LoginModel();
    return View(model);
}
 
[AllowAnonymous]
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
    if (ModelState.IsValid) //Required, string length etc
    {
        var userStore = new UserRepository();
        var user = userStore.FindUser(model.UserName, model.Password);
        if (user != null)
        {
            //simple
            //FormsAuthentication.SetAuthCookie(user.Name, false);
 
            //manually set cookies
            SetAuthCookie(user.Name, user.RolesList.ToArray());
 
            //redirect to returnUrl
            if (!string.IsNullOrEmpty(returnUrl) &&
                Url.IsLocalUrl(returnUrl) &&
                !returnUrl.Equals("/Error/NotFound", StringComparison.OrdinalIgnoreCase))
            {
                return Redirect(returnUrl);
            }
            return Redirect("~/");
        }
        ModelState.AddModelError("UserName", "User or password not found");
    }
    return View(model);
}
 
private void SetAuthCookie(string userName, string[] roles)
{
    var userData = string.Join(",", roles); //could JsonConvert.SerializeObject(obj)
    var authTicket = new FormsAuthenticationTicket(
          1, //version
          userName,
          DateTime.Now, //issue date
          DateTime.Now.AddMinutes(30), //expiration
          false//isPersistent
          userData,
          FormsAuthentication.FormsCookiePath); //cookie path
    var cookie = new HttpCookie(FormsAuthentication.FormsCookieName,
                                FormsAuthentication.Encrypt(authTicket));
    Response.Cookies.Add(cookie);
}

Sign-out is simple

public ActionResult SignOut()
{
    FormsAuthentication.SignOut();
    return Redirect("~/");
}

To go with the custom cookie, global.asax has the following. NB: AuthenticateRequest to create the principal (we let FormsAuthentication do it by default, PostAuthenticateRequest to add roles)

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
    var context = HttpContext.Current;
    if (context.User == null || !context.User.Identity.IsAuthenticated)
    {
        return;
    }
 
    var formsIdentity = context.User.Identity as FormsIdentity;
    if (formsIdentity == null)
    {
        return;
    }
 
    var id = formsIdentity;
    var ticket = id.Ticket;
 
    var userData = ticket.UserData; // Get the stored user-data, in this case, our roles
    var roles = userData.Split(',');
    var userPrincipal = new GenericPrincipal(formsIdentity, roles);
    //set both thread principal and HttpContext user
    Thread.CurrentPrincipal = Context.User = userPrincipal;
}

Razor view

<div class="navbar-collapse collapse">
    <ul class="nav navbar-nav">
        <li>@Html.ActionLink("Home", "Index", "Home")</li>
        <li>@Html.ActionLink("Secure", "Secure", "Home")</li>
    </ul>
    @if (User.Identity.IsAuthenticated)
    {
        <ul class="nav navbar-nav navbar-right">
            <li class="navbar-text">Logged in as @User.Identity.Name</li>
            <li>@Html.ActionLink("Sign out","SignOut","Account")</li>
        </ul>
    }
</div>

WebAPI

The MVC [System.Web.Mvc.Authorize()] attribute doesn't work on WebAPI, which has [System.Web.Http.Authorize()].

using System;
using System.Configuration;
using System.Web;
using System.Web.Http.Controllers;
 
namespace Website
{
    /// <summary>
    /// Restrict access to MVC controllers to roles specified in AppSettings SecurityRole:Write
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class WriteAuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            var isAuthorized = base.AuthorizeCore(httpContext);
            if (!isAuthorized)
            {
                return false;
            }
            var writeRole = ConfigurationManager.AppSettings["SecurityRole:Write"];
            if (!string.IsNullOrEmpty(writeRole))
            {
                return httpContext.User.IsInRole(writeRole);
            }
            return true;
        }
    }
 
    /// <summary>
    /// Restrict access to WebAPI controllers to roles specified in AppSettings SecurityRole:Write
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class WriteAuthorizeApiAttribute : System.Web.Http.AuthorizeAttribute
    {
        protected override bool IsAuthorized(HttpActionContext actionContext)
        {
            var isAuthorized = base.IsAuthorized(actionContext);
            if (!isAuthorized)
            {
                return false;
            }
            var writeRole = ConfigurationManager.AppSettings["SecurityRole:Write"];
            if (!string.IsNullOrEmpty(writeRole))
            {
                return actionContext.RequestContext.Principal.IsInRole(writeRole);
            }
            return true;
        }
    }
}

Add global filters onto GlobalConfiguration in WebApiConfig:

config.Filters.Add(new AuthorizeAttribute { Roles = "Reader" });

ASP Forms

In your login page :

protected void btnLogin_Click(object sender, EventArgs e)

{

    string userName = txtUserName.Text.Trim();

    string password = txtPassword.Text.Trim();

    //if (Membership.ValidateUser(userName, password)) //membership provider

    if (ValidateUser(userName, password)) //local validation

    {

        //if using redirection

        FormsAuthentication.RedirectFromLoginPage(userName, false);

        //otherwise just set cookie

        //FormsAuthentication.SetAuthCookie(userName, false);

    }

    else

    {

        Page.Validators.Add(new BusinessValidationError("Invalid UserID and Password"));

    }

}

To implement a custom MembershipProvider see msdn sample (and here for web.config to set the membership defaultProvider)

To logout manually (you can also just use the asp:LoginStatus control):

FormsAuthentication.SignOut();

Response.Redirect(FormsAuthentication.GetLoginPage(null));

//if you did NOT specify [email protected]=UseCookies (or are using cookieless) you are automatically redirected

Roles

To do role management (User.IsInRole(x), [email protected], sitemap roles) you have to manually create a FormsAuthenticationTicket and put it in a cookie (RoleManager creates a separate role cookie). NB: you have about 1k of the 4k cookie size maximum for the role list- otherwise use Cache (you can't use Session, it isn't available early enough).

string userRoles = "Admin, PowerUser"; //from database?

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(

        1,                          // version

        userName,                   // user name

        DateTime.Now,               // issue time

        DateTime.Now.AddMinutes(30),// expires

        false,                      // persistent

        userRoles                   // user data

        );

 

HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));

cookie.Secure = FormsAuthentication.RequireSSL;

cookie.Domain = FormsAuthentication.CookieDomain;

cookie.HttpOnly = true; //a little extra security

Response.Cookies.Add(cookie);

Response.Redirect("Secure.aspx");

Now wire this in the global.asax (or use an HttpModule)

void Application_OnAuthenticateRequest(object sender, EventArgs e)

{

    HttpContext c = HttpContext.Current;

    if (c.Request.IsAuthenticated)

    {

        FormsIdentity id = (FormsIdentity)c.User.Identity;

        string[] roles = id.Ticket.UserData.Split(',');

        System.Security.Principal.GenericPrincipal p =

            new System.Security.Principal.GenericPrincipal(c.User.Identity, roles);

        Context.User = System.Threading.Thread.CurrentPrincipal = p;

    }

}

Simple Authentication In Web.Config

For quick and simple/dirty security, you can put users directly into the web.config.

Nested web.config: You must only set <authentication> on the top level. You can't set it on subfolder web.config or in <location>. You should instead use different <authorization> sections.

<authentication mode="Forms">

    <forms loginUrl="~/Admin/Login.aspx">

        <credentials passwordFormat="Clear">

            <user name="Martin" password="secret"/>

        </credentials>

    </forms>

</authentication>

Then just use the login control.

<asp:Login ID="Login1" runat="server" DisplayRememberMe="False" VisibleWhenLoggedIn="False"
    OnAuthenticate="Login1_Authenticate" />

<script runat="server">

    protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)

    {

        e.Authenticated = FormsAuthentication.Authenticate(Login1.UserName, Login1.Password);

    }

</script>

Saving new users into web.config. If you're doing this, you really should be using a database, but hey ho. Also you really should use SHA1 format.

if (!Page.IsValid) return;

string userName = Server.HtmlEncode(txtName.Text);

string pw = Server.HtmlEncode(txtPassword.Text);

Configuration config = WebConfigurationManager.OpenWebConfiguration("~/");

//also (AuthenticationSection)WebConfigurationManager.GetWebApplicationSection("system.web/authentication") but users is readonly;

AuthenticationSection auth = (AuthenticationSection)config.SectionGroups["system.web"].Sections["authentication"];

string passwordFormat = auth.Forms.Credentials.PasswordFormat.ToString();

if (passwordFormat != "Clear")

    pw = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, passwordFormat);

auth.Forms.Credentials.Users.Add(new FormsAuthenticationUser(userName, pw));

try

{

    config.Save();

    Response.Redirect(Request.CurrentExecutionFilePath);// Redirect to self.

}

catch (ConfigurationErrorsException ex)

{

    Label1.Text = "ASP.NET process account (ASPNET or Network Service) must have write permission granted for the Web.config file<br/>";

    Label1.Text += "Manually copy this xml into your web.config forms/credentials section:<br/>";

    Label1.Text += string.Format("&lt;user name=\"{0}\" password=\"{1}\" /&gt;", userName, pw);

}