Question

I've been playing with some of the MVC tutorials on making a database website with C# and have a question about how to make a section of the website only accessible ONCE a user has logged in with a username and password.

I have a logon page (code below), which takes the username and password, and then authenticates a user against a database record. Once you've clicked the "login" button the return URL takes you into an Admin section of the website (full path is: http://localhost:53559/Data/update). This bit I'm happy with. However, the issue I have is that the "update" page is still accessible if you've NOT logged in I.e. if I enter in the browser the path above (http://localhost:53559/Data/update) without ever logging in first it will load no problem).

How do I restrict the update page, so it is only available once the user has logged in?

(NB: total beginner, small words please!)

==================================================================================

Controller code for the logon:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using DFAccountancy.Models;

namespace DFAccountancy.Controllers
{
public class AdminController : Controller
{

    //
    // GET: /Admin/LogOn

    public ActionResult LogOn()
    {
        return View();
    }

    //
    // POST: /Account/LogOn

    [HttpPost]
    public ActionResult LogOn(LogOnModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            if (Membership.ValidateUser(model.UserName, model.Password))
            {
                FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                    && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                {
                    return Redirect(returnUrl);
                }
                else
                {
                    return RedirectToAction("Update", "Data");
                }
            }
            else
            {
                ModelState.AddModelError("", "The user name or password provided is incorrect.");
            }
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

    //
    // GET: /Account/LogOff

    public ActionResult LogOff()
    {
        FormsAuthentication.SignOut();

        return RedirectToAction("Index", "Home");
    }

==================================================================================

This is the View code for the Update page (which is the Admin section, and should only be accessible once the user has logged in):

@model DFAccountancy.Models.Data

@{
    ViewBag.Title = "Update";
}



<h2>Update</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">        </script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"         type="text/javascript"></script>

<script type="text/javascript">
$(function () { $("#cl_button1").click(function () { $("#para1").val(""); }); });
$(function () { $("#cl_button2").click(function () { $("#para2").val(""); }); });
</script>

@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
    <legend>Data</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.para1)
    </div>
    <div class="editor-field">
        @Html.TextAreaFor(model => model.para1, new { cols = 75, @rows = 5 })
        @Html.ValidationMessageFor(model => model.para1)
    <input id="cl_button1" type="button" value="Clear Paragraph" />
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.para2)
    </div>
    <div class="editor-field">
        @Html.TextAreaFor(model => model.para2, new { cols = 75, @rows = 5 })
        @Html.ValidationMessageFor(model => model.para2)
        <input id="cl_button2" type="button" value="Clear Paragraph" />
    </div>

    <p>
        <input type="submit" value="Update" />
        <input type="reset" value="Re-Set to begining" />
    </p>

</fieldset>
}

<div>
@Html.ActionLink("Back to List", "Index")
</div>

==================================================================================

This is the Controller code (DataController) that sits behind the Update View page:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DFAccountancy.Models;

namespace DFAccountancy.Controllers
{ 
    public class DataController : Controller
    {
    private DataDBContext db = new DataDBContext();

    //
    // GET: /Data/

    public ViewResult Index()
    {
        return View(db.Data.ToList());
    }

    //
    // GET: /Data/Details/5

    public ViewResult Details(string id)
    {
        Data data = db.Data.Find(id);
        return View(data);
    }



    //
    // GET: /Data/Update

    public ActionResult Update()
    {
        var model = db.Data.FirstOrDefault();
        return View(model);
    }

    //
    // POST: /Data/Update

    [HttpPost]
    //[Authorize(Roles = "Administrator")]  //Created Validataion so inaccessible from outside
    [ValidateInput(false)]
    public ActionResult Update(Data data)
    {
        if (ModelState.IsValid)
        {
            data.ID = 1; //EF need to know which row to update in the database.       
            db.Entry(data).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index", "Home");
        }
        return View(data);
    }


}
}
Was it helpful?

Solution

Use the [Authorize] filter. You can apply it to a controller, or to an individual action.

[Authorize]
public class DataController : Controller
{...

Or

[Authorize]
public ActionResult Update()
{...

As a side note, you are not closing your DB connection from what I can see. Your data context needs to have .Dispose() called on it when it is finished.

EDIT

Moreover, it looks like your get method is not decorated with the authorize, which is why anyone can navigate there. Only the post is decorated, or was until commented out, with the authorize filter. [HttpGet] is used for a basic request, whereas the [HttpPost] generally comes from a form post (Sometimes it is done through ajax).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top