Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#.NET Using isAuthenticated

Tags:

c#

asp.net-mvc

Im using the MVC format to create a website. Right now all it does is manage users from an SQL server. What i'm trying to do now is have the user log in and then be able to manage the Users. From the Login page it should go to the Index of the Account but I only want this page to be viewable by authenticated users. It works fine if I:

1)set the function in the controler to [AllowAnonymous] (This is not what i want)

2)Allow Windows Authentication (Which is not what I want because once I deploy, it'll be on the web)

It really just boils down to how do I authenticate a user and then have that authentication persist.

Here is the login page:

@model myWebsite.Models.LoginModel

@{
    ViewBag.Title = "Login";
    ViewBag.ReturnUrl = "Index";
}

<h2>Login</h2>

@using (Html.BeginForm("Login", "Login", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
    <div class="form-horizontal">
        <h4>Login</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger"})
        <div class="form-group">
            @Html.LabelFor(Model => Model.UserName, new { @class = "control-label col-md-2"})
            <div class="col-md-10">
                @Html.TextBoxFor(Model => Model.UserName, new { @class = "col-md-2 control-label"})
                @Html.ValidationMessageFor(Model => Model.UserName, "" , new { @class = "text-danger"})
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(Model => Model.Password, new { @class = "control-label col-md-2"})
            <div class="col-md-10">
                @Html.TextBoxFor(Model => Model.Password, new { @class = "col-md-2 control-label"})
                @Html.ValidationMessageFor(Model => Model.Password, "" , new { @class = "text-danger"})
            </div>
        </div>
        <div class="form-group">
            <input type="submit" value="Log In" class="btn btn-default" />
        </div>
    </div>
}

This is the partial portion of every page

@using Microsoft.AspNet.Identity;

@if (Request.IsAuthenticated)
{
    using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
    {
        @Html.AntiForgeryToken()
        <ul class="nav navbar-nav navbar-right">
            <li>@Html.ActionLink("Hello "  + User.Identity.GetUserName() + "!", "Index" , "Manage", routeValues: null, htmlAttributes: new { title = "Manage" } )</li>
        </ul>
    }
}
else
{
    <ul class="nav navbar-nav navbar-right">
        <li>@Html.ActionLink("Register", "Create", "Login", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
        <li>@Html.ActionLink("Log in", "Login", "Login", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
    </ul>
}

This is the controller

    [AllowAnonymous]
    // GET: Login
    public ActionResult Login()
    {
        return View();
    }


    [AllowAnonymous]
    // GET: Login
    public ActionResult Login()
    {
        return View();
    }

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult Login(LoginModel model, string retunUrl)
    {

        /* 
        if (!ModelState.IsValid)
        {
            Console.WriteLine("IS NOT VALID");
            return View(model);
        }
       */
        String UserName = model.UserName;
        String Password = model.Password;

        LoginContext LC = new LoginContext();
        LoginModel ValidUser = LC.UserList.Single(Person => Person.UserName == UserName && Person.Password == Password);

        if (ValidUser != null)
        {
            return Redirect("Index");
        }
        return View(model);
    }




    // GET: Login Index of users
    [AllowAnonymous]
    public ActionResult Index()
    {
        return View(db.UserList.ToList());
    }
like image 599
Frank Navarrete Avatar asked Mar 12 '23 19:03

Frank Navarrete


1 Answers

The Old Way™

If all you care about is persisting the fact that a user gave you valid credentials, your simplest option is probably FormsAuthentication:

FormsAuthentication.SetAuthCookie(model.UserName, false);

and

FormsAuthentication.SignOut();

These require that the FormsAuthentication module is active, so you would look for a line like this in the web.config:

<remove name="FormsAuthentication" />

and remove it, and either add or update the authentication section:

<authentication mode="Forms">
  <forms loginUrl="~/account/login" timeout="2880" defaultUrl="~/" protection="All" />
</authentication>

With these settings, ASP.NET knows to build the Identity and Principle from the cookie generated by FormsAuthentication.SetAuthCookie.

The Right(ish) Way™

That being said, FormsAuthentication is not the recommended path at this point, both for it's reliance on System.Web, and the fact that it isn't claims aware.

You can accomplish a minimum setup using OWIN that does yield a claims-aware Identity. If you started with a newer ASP.NET project template, you should have a Startup.Auth.cs file in the App_Start folder, or you can add one. The minimum code to use cookie-based authentication with OWIN is:

using Microsoft.AspNet.Identity;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Owin;

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            LoginPath = new PathString("/account/login"),
            LogoutPath = new PathString("/account/logout"),
            CookieName = ".YOUR_COOKIE_NAME_HERE",
            SlidingExpiration = true, 
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            AuthenticationMode = AuthenticationMode.Active
        });
    }
}

Then, when you authenticate your user, you do something like:

var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, model.UserName));

var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
HttpContext.Current.Request.GetOwinContext().Authentication.SignIn(identity);

And to sign out:

HttpContext.Current.Request.GetOwinContext().Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);

You will also need to set the following value in your Global.asax file:

using System.Web.Helpers;
using System.Security.Claims;

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        // ... your other startup/registration code ...

        AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;
    }
}

The Request.IsAuthenticated just checks to see if a non-anonymous Identity has been established on the current request context, so either option noted above will work.

As an aside: you really should not be storing passwords in plain text. When you create your user records, use Crypto.HashPassword to create a salted hash of the password, storing that instead, and then use Crypto.VerifyHashedPassword when checking if the user entered the correct password. You can find the Crypto documentation here.

like image 152
Tieson T. Avatar answered Mar 27 '23 04:03

Tieson T.