MVC ASP.NET - Manually authorize someone and persist the authorization via Forms Authentication

13,494

Solution 1

In forms authentication isn't the proof of who you are in th forms authentication cookie.? With that in mind couldn't you create the ticket in a custom login form without having to create a custom provider? I would definitely think you could. Do a quick test and create a forms authentication ticket and see if the out of the box membership provider considers the user authenticated.

I was curious-- so here is some code..

Model

public class SignInViewModel
{
    public string Username { get; set; }
    public string Password { get; set; }
}

Controller

public class SignInController : Controller
{

    public ActionResult Index()
    {
        var model = new SignInViewModel {};
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(SignInViewModel model)
    {
        if (model.Username == "Fred" && model.Password == "Mertz")
        {
            FormsAuthentication.SetAuthCookie(model.Username, false);
            return RedirectToAction("Secure");
        }
        return View(model);
    }

    [Authorize]
    public ActionResult Secure(SignInViewModel model)
    {
        return View();
    }

    [Authorize]
    public ActionResult Logout(SignInViewModel model)
    {
        FormsAuthentication.SignOut();
        return RedirectToAction("Index");
    }

Index.cshtml

@using (Html.BeginForm()) {
    <fieldset>
        <legend>SignInViewModel</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Username)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Username)
            @Html.ValidationMessageFor(model => model.Username)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Password)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Password)
            @Html.ValidationMessageFor(model => model.Password)
        </div>

        <p>
            <input type="submit" value="Login" />
        </p>
    </fieldset>
}

Secure.cshtml

<h2>Secure</h2>
@Html.ActionLink("Logout", "Logout")

Solution 2

I may be over simplifying this, but the way I read this is the following:

  1. If a user is not authenticated, you have a form that you collect the username/password
  2. The results of that form are passed to a web service for authorization
  3. If that authorization is successful, you need a way to let the web application know that they have signed in.
  4. If they are authenticated, do stuff

If the above is correct, you do not need a membership provider. The [Authorize] attribute simply looks that the forms authentication cookie to see if it has been set and is valid for the current lifetime of the cookie. This authentication cookie stores the username of the user and the expiration time of the cookie (and other stuff, but not important here).

Given that, you only need to set your web.config configuration element and have a method to set the authentication cookie.

Web.Config

<system.web>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880" />
    </authentication>
</system.web>

Logon URL GET action

public ActionResult Logon(){
   //if the user is logged in, send the to the home page
   if(httpContext.User.Identity.IsAuthenticated_{
        Return RedirectToAction("Index", "Home");
   }
   Return this.View(new LoginViewModel());
}

Logon URL POST action

[HttpPost]
public ActionResult Logon(LoginViewModel model){
   //Check for model errors
   if(!ModelState.IsValid()){
       Return this.View(model);
   }

   //Validate against web service - return error if false
   if(!CheckClientsWebService(model.UserName, model.Password)){
       ModelState.AddModelError("","The username or password is invalid");
       Return this.View(model);
   } 

   //Manually set the authentication cookie
   FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);  
   //Send them on to the home page, they now have a authorization cookie
   Return RedirectToAction("Index", "Home");
}

Once you have called the .SetAuthCookie() function, the user will now have an authentication ticket and calls to HttpContext.User.Identity.IsAuthenticated will be true as long as the cookie has not expired and you can get the user name from HttpContext.User.Identity.Name

Share:
13,494
contactmatt
Author by

contactmatt

Updated on June 03, 2022

Comments

  • contactmatt
    contactmatt almost 2 years

    I want the benefits of form authentication in ASP.NET. I want it to persist the authorization for me and such, but there's one thing different about my situation; I want to authenticate against a simple web service (specifically provided by the client).

    I have my code in place to look at the web place and see if they should be authorized, but how do I set the cookie[?] or authorization flag in ASP.NET that they know the current user is authorized.

    Basically...

    if (HttpContext.Current.User.Identity.IsAuthenticated)
    // we're all good
    
    //Other wise...
    bool success = CheckClientsWebService(string username, string password);
    
    if (success)
    // Somehow tell .NET that they're authorized
    

    *Note: This is a fairly simple service that does not deal with groups or roles. Simply checking if a user is okay to view the site.

  • Rahul Patel
    Rahul Patel over 8 years
    Hi, FormsAuthentication.SetAuthCookie(model.Username, false); is not working for me. I am using MVC 5
  • Kurt Wagner
    Kurt Wagner over 8 years
    @RahulPatel are you using the System.Web.Security namespace? It should be supported in MVC5 / ASP.NET 4.5+ msdn.microsoft.com/en-us/library/…
  • Tommy
    Tommy about 8 years
    @RahulPatel - MVC 5 comes with ASP.NET Identity enabled by default which disables FormsAuthentication.