So here is the situation, I have a loginpartial.cshtml, which I put on the page with RenderAction
this loginpartial contains an IsAuthenticated, where if the user is not authenticated it shows the login form.
Secondly, I have a manage page which contains some fields like firstname etc.
When I push the save button, it saves it nicely to the database. However, the login form also gets called, and I have no idea why.
layout.cshtml:
#{Html.RenderAction("Login", "User");}
LoginPartial.cshtml:
<div class="nav navbar-nav navbar-right">
#if (User.Identity.IsAuthenticated)
{
<div>No login</div>
}
else
{
using (Html.BeginForm("Login", "User", FormMethod.Post))
{
#Html.AntiForgeryToken();
#Html.ValidationSummary(true, "Login failed.")
<div class="Login">
//fields here
</div>
}
}
</div>
UserController Login:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(User user)
{
if (ModelState.IsValid)
{
if (isValid(user.Email, user.Password))
{
using (MVCV2DbContext MVCV2DbContext = new MVCV2DbContext())
{
var users = MVCV2DbContext.Users.Single(u => u.Email == user.Email);
FormsAuthentication.SetAuthCookie(users.ID.ToString(), false);
//FormsAuthentication.SetAuthCookie(user.Email, false);
}
return RedirectToAction("Index", "User");
}
}
return View(user);
}
manage.cshtml:
using (Html.BeginForm("Manage", "User", FormMethod.Post))
{
#Html.AntiForgeryToken();
#Html.ValidationSummary(true, "Not all good")
<div>
//fields here
</div>
}
usercontroller manage:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Manage(User_Details users)
{
if (ModelState.IsValid)
{
int U_ID = Convert.ToInt32(GetUserIDFromCookie());
using (MVCV2DbContext MVCV2DbContext = new MVCV2DbContext())
{
var user = MVCV2DbContext.User_Details.SingleOrDefault(u => u.User_ID == U_ID);
if (user != null)
{
user.User_FirstName = users.User_FirstName;
user.User_Insertions = users.User_Insertions;
user.User_LastName = users.User_LastName;
MVCV2DbContext.SaveChanges();
}
}
}
return View();
}
Instead of if(User.Identity.IsAuthenticated) try Request.IsAuthenticated
Also what is your debugging saying?
#{Html.RenderAction("Login", "User");}
in your layout file
will call the action method when ever the view is rendered
you can get around this by moving
if(User.Identity.IsAuthenticated) ... don't run auth code
out of the view and into the layout view, or controller (with appropriate changes to the IsAuthenticated Test)
Related
i'm making a webbapplication with ASP.NET MVC and im trying to edit my list of objects. If i for example add a product to the site and then click on edit for that product to change the prize i just get a new object with the new prize instead of changing the prize to the product.
So the problem is that instead of updating the products it just adds a new one.
this is how my controller for the products looks like:
using auktioner_MarcusR91.Data;
using auktioner_MarcusR91.Models;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace auktioner_MarcusR91.Controllers
{
public class InventoryController : Controller
{
private readonly AppDbContext _db;
public InventoryController(AppDbContext db)
{
_db = db;
}
public IActionResult Index()
{
IEnumerable<Inventory> objInventoryList = _db.Inventories;
return View(objInventoryList);
}
//GET
public IActionResult Create()
{
return View();
}
//Post
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Inventory inventory)
{
_db.Inventories.Add(inventory);
_db.SaveChanges();
return RedirectToAction("index");
}
//GET
public IActionResult Edit(int? id)
{
if (id == 0 || id == 5)
{
return NotFound();
}
var inventoryFromDb = _db.Inventories.Find(id);
if (inventoryFromDb == null)
{
return NotFound();
}
return View(inventoryFromDb);
}
//Post
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(Inventory inventory)
{
if (ModelState.IsValid)
{
_db.Inventories.Update(inventory);
_db.SaveChanges();
return RedirectToAction("index");
}
return View(inventory);
}
}
}
I think there is something wrong in my controller.
However here is also my view for when i edit a product:
#model Inventory
<form method = "post" asp-action = "Edit">
<div class = "border p-3 mt-4">
<div class = "row pb-2">
<h2 class = "text-primary">Edit Inventory</h2>
<hr />
</div>
<div class = "mb-3">
<label asp-for ="inventoryName"></label>
<input asp-for = "inventoryName" />
<label asp-for ="finalPrize"></label>
<input asp-for = "finalPrize" />
<label asp-for ="inventoryDesc"></label>
<input asp-for = "inventoryDesc" />
<p>1 för "Transport</p>
<p>2 för "Smycken"</p>
<p>3 för "Hushåll"</p>
<p>4 för "Dekoration"</p>
<select asp-for = "categoryId">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
</select>
</div>
<button type = "submit" class = "btn btn-primary" width = "100px">Update</button>
<a asp-controller = "Inventory" asp-action = "index" class = "btn btn-secondary" style = "width: 100px">Back to products</a>
</div>
</form>
You have to add a primary key inventoryId as a hidden input, without this key , you inventory instance looks like a new one for EF.
And since you are using [ValidateAntiForgeryToken] in the action, add this to view with another form syntax
#using (Html.BeginForm("Edit", "Inventory", FormMethod.Post))
{
#Html.AntiForgeryToken()
<input type="hidden" asp-for="inventoryId" value="#Model.inventoryId" />
....
<button type = "submit" class = "btn btn-primary" width = "100px">Update</button>
<a asp-controller = "Inventory" asp-action = "index" class = "btn btn-secondary" style = "width: 100px">Back to products</a>
</div>
}
and IMHO your update code could be like this
if (ModelState.IsValid)
{
var inventoryFromDb = _db.Inventories.Find(inventory.inventoryId);
if (inventoryFromDb == null)
{
return NotFound();
}
_db.Entry(inventoryFromDb).CurrentValues.SetValues(inventory);
var result= _db.SaveChanges();
}
You have to send your record id to the controller by clicking update button of the record . something like this :
<a class="btn btn-warning btn-sm btn-margin" asp-controller="ContextController" asp-action="UpdateAction" ***asp-route-id="#item.Id***">Update</a>
which #item is the object of the model sent to the view .
And the action would be :
[HttpGet]
public IActionResult UpdateAction(int id)
{
Model record = _Context.GetById(id);
return View("UpdateFormPageOrModal",record);
}
And after updating the form and clicking the submit button of the view data will send to action :
[HttpPost]
public IActionResult UpdateAction(Model record)
{
var result = _Context.UpdateBy(record);
ViewData["Result"] = result.Message;
if (result.IsSucceeded)
{
_UnitOfWork.Save();
return RedirectToAction("TheGridView");
}
return View("UpdateView",record);
}
where UpdateBy() method should be like this :
public void UpdateBy(T entity)//entity is an object of the DbSet<Model>
{
var state = _Context.Entry(entity).State;
if (state == EntityState.Detached)
{
_Context.Attach(entity);
}
_Context.Entry(entity).State = EntityState.Modified;
}
I am using asp.net razor engine. I have a delete button and the first time I press it, it works. The second time the url repeats the function and does not work.
This is the first time I use the Delete button
This is the second time I use Delete. Notice the URL is del/del. Trying to avoid that second del.
Here is my controller
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using DapperApp.Factory;
using login.Models;
using login.Controllers;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Http;
namespace login.Controllers
{
public class HomeController : Controller
{
private readonly UserFactory userFactory;
public HomeController(UserFactory user) {
userFactory = user;
}
// GET: /Home/
[HttpGet]
[Route("")]
public IActionResult Index()
{
return View();
}
[HttpPost]
[Route("")]
public IActionResult Register(Home model)
{
if(!ModelState.IsValid)
{
return View("Index", model);
}
PasswordHasher<Home> Hasher = new PasswordHasher<Home>();
model.Password = Hasher.HashPassword(model, model.Password);
userFactory.Add(model);
TempData["message"] = false;
return RedirectToAction("Index");
}
[HttpPost]
[Route("login")]
public IActionResult Login(Home model)
{
if(model.Password == null || model.Email == null){
TempData["login"] = false;
return RedirectToAction("Index");
}
var pass = userFactory.FindByEmail(model);
var Hasher = new PasswordHasher<Home>();
if(pass == null)
{
TempData["login"] = false;
return RedirectToAction("Index");
}
// Pass the user object, the hashed password, and the PasswordToCheck
if(0 != Hasher.VerifyHashedPassword(model, pass.Password, model.Password))
{
TempData["first_name"] = pass.First_Name;
TempData["last_name"] = pass.Last_Name;
TempData["id"] = pass.Id;
HttpContext.Session.SetString("Id", pass.Id.ToString());
ViewBag.Quotes = userFactory.FindAll();
return View();
}
TempData["login"] = false;
return RedirectToAction("Index");
}
[HttpPost]
[Route("addQuote")]
public IActionResult AddQuote(Quotes model)
{
var test = HttpContext.Session.GetString("Id");
if(!ModelState.IsValid)
{
TempData["id"] = test;
model.Users_id = Convert.ToInt32(test.ToString());
var user2 = userFactory.FindById(model.Users_id);
TempData["first_name"] = user2.First_Name;
TempData["last_name"] = user2.Last_Name;
ViewBag.Quotes= userFactory.FindAll();
return View("Login", model);
}
if(test == null){
return RedirectToAction("Index");
}
model.Users_id = Convert.ToInt32(test.ToString());
userFactory.addQuote(model);
var user = userFactory.FindById(model.Users_id);
TempData["id"] = test;
TempData["first_name"] = user.First_Name;
TempData["last_name"] = user.Last_Name;
ViewBag.Quotes = userFactory.FindAll();
return View("Login", model);
}
[HttpGet]
[Route("logout")]
public IActionResult Logout()
{
return RedirectToAction("Index");
}
[HttpGet]
[Route("del/{id}")]
public IActionResult Del(int Id) // This is my delete method
{
userFactory.DeleteByID(Id);
ViewBag.Quotes2= userFactory.FindAll();
var test = HttpContext.Session.GetString("Id");
var user = userFactory.FindById(Convert.ToInt32(test));
TempData["first_name"] = user.First_Name;
TempData["last_name"] = user.Last_Name;
TempData["id"] = test;
return View("Login");
}
}
}
Here is my cshtml page
<h1>Hello #TempData["first_name"] #TempData["last_name"]</h1>
#if(TempData["first_name"]!= null)
{
}
#model login.Models.Quotes
<h1>Add Your Quote</h1>
#using(Html.BeginForm("AddQuote","Home"))
{
<p>
<label>Your Quote</label>
#Html.TextAreaFor(d=>d.quotes)
#Html.ValidationMessageFor(d => d.quotes)
</p>
<input type="submit" name="submit" value="Add my quote!"/>
}
<form action="logout" method="get">
<input type="submit" name="submit" value="Log Out"/>
</form>
<div >
#{
if(ViewBag.Quotes != null)
{
foreach(var quotes in ViewBag.Quotes)
{
//If there are any errors for a field...
<p><q>#quotes.quotes</q></p>
<p class="wrapper">-#quotes.First_Name #quotes.Last_Name at #quotes.Created_At.ToString("hh"):#quotes.Created_At.ToString("mm")
#quotes.Created_At.ToString("tt") #quotes.Created_At.ToString("MMM") #quotes.Created_At.ToString("dd")
#quotes.Created_At.ToString("yyyy")</p>
if(#quotes.Users_id == Convert.ToInt32(TempData["id"].ToString()))
{
<form action="del/#quotes.Id_Quotes" method="get">
<input type="submit" name="submit" value="Delete"/>
</form>
}
}
}
if(ViewBag.Quotes2 != null)
{
foreach(var quotes in ViewBag.Quotes2)
{
//If there are any errors for a field...
<p><q>#quotes.quotes</q></p>
<p class="wrapper">-#quotes.First_Name #quotes.Last_Name at #quotes.Created_At.ToString("hh"):#quotes.Created_At.ToString("mm")
#quotes.Created_At.ToString("tt") #quotes.Created_At.ToString("MMM") #quotes.Created_At.ToString("dd")
#quotes.Created_At.ToString("yyyy")</p>
if(#quotes.Users_id == Convert.ToInt32(TempData["id"].ToString()))
{
<form action="del/#quotes.Id_Quotes" method="get">
<input type="submit" name="submit" value="Delete"/>
</form>
}
}
}
}
</div>
Your form action is using a relative (not a concrete) reference, meaning it will append the action to the end of the current url each time you submit the form. Try making the action the absolute url of your get request. In this case that would mean:
<form action="del/#quotes.Id_Quotes" method="get">
<input type="submit" name="submit" value="Delete"/>
</form>
becomes
<form action="/del/#quotes.Id_Quotes" method="get">
<input type="submit" name="submit" value="Delete"/>
</form>
Also, just to nitpick, when deleting things (or adding and editing things) to a database you should use a POST request. They provide an additional level of security.
I am new here and I was wondering if anyone can help me.
I developed a website ( ASP.net , MVC , C#) and it was working fine, since 2 months ago I used the Kendo UI framework to improve some page design and grids , .. and since then I have a problem with login functionality. I can login fine but all the users who are using our company network have a problem with login ( they can log in but they are redirected to Unauthorised access page !) I have not done any changes in the login page at all. since I cannot find the reason for the problem I just ask the to try to login again or login / logout or empty the cache ...
Any one have any idea that what might go wrong here?
thanks
sorry here is my code for login page
<div class="col-md-4">
<h4>Login
</h4>
<div>
<div>
#using (Html.BeginForm()) {
#Html.ValidationSummary(false);
<div class="form-group">
#Html.LabelFor(m => m.Username)
#Html.TextBoxFor(m => m.Username, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Username)
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Password)
</div>
<div class="form-group">
<div class="checkbox">
<label>
#Html.CheckBoxFor(m => m.RememberMe) Remember me
</label>
</div>
</div>
<button type="submit" class="submit btn btn-primary"><i class="icon-lock"></i>Login</button>
}
</div>
</div>
</div>
</div>
<hr />
<div class="slider-wrapper theme-default">
<div class="ribbon"></div>
<div id="slider" class="nivoSlider">
<img src="#Url.Content("~/Content/img/search.png")" title="Detailed Search Facility" />
<img src="#Url.Content("~/Content/img/charts.png")" title="Exception Charts" />
<img src="#Url.Content("~/Content/img/mtbe.png")" title="Mean Time Between Exception Analysis" />
<img src="#Url.Content("~/Content/img/pm-compliance.png")" title="PM Compliance" />
<img src="#Url.Content("~/Content/img/cost-analysis.png")" title="Cost Benefit Analysis" />
</div>
</div>
#section Scripts{
<script>
$(window).load(function () {
$('#slider').nivoSlider();
});
</script>
}
Controller code:
public class AccountController : Controller {
private HashUtility hashUtility = new HashUtility();
[Authorize]
public ActionResult Index() {
var companyName = this.GetCurrentCompanyName();
if (string.IsNullOrEmpty(companyName)) {
return RedirectToAction("SelectCompany");
}
return RedirectToAction("Index","Home");
}
#region Select Company
[HasPermission(Category.SELECT_COMPANY)]
public ActionResult SelectCompany() {
this.SetTitle("Select Company");
var model = new List<CompanyModel>();
using (var context = DbConnectionFactory.CreateDataContext()) {
model = context.Companies
.OrderBy(c => c.Name)
.Select(c => new CompanyModel{
CompanyId = c.CompanyId,
Name = c.Name,
HasLogo = c.Logo!=null && c.Logo.Length > 0
})
.ToList();
}
return View(model);
}
#endregion
#region Login
public ActionResult Login() {
this.SetTitle("Login");
if (!Request.IsAuthenticated) {
this.SetTitle("Login");
return View();
}
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Login(LoginModel model) {
if (!ModelState.IsValid) {
return View(model);
}
bool loginFailed = false;
string companyName = null;
using (var context = DbConnectionFactory.CreateDataContext()) {
var user = context.Users.SingleOrDefault(a => (a.Username == model.Username || a.EmailAddress == model.Username));
if (user == null) {
ModelState.AddModelError(string.Empty,
"An account does not exist with the user name provided.");
return View(model);
}
if (user.IsLocked) {
ModelState.AddModelError(string.Empty,
"This user account is disabled, please contact helpdesk for support.");
return View(model);
}
if (hashUtility.VerifyHashString(model.Password, user.Password, user.Salt)) {
FormsAuthentication.SetAuthCookie(user.Username, model.RememberMe);
companyName = user.Company!=null ? user.Company.Name : null;
//model.Accessed = DateTime.Now;
//user.Accessed = model.Accessed;
} else {
ModelState.AddModelError(string.Empty,
"Incorrect username or password provided for this account, please verify and try again.");
loginFailed = true;
}
}
if (loginFailed) {
return View(model);
} else if (!string.IsNullOrWhiteSpace(model.ReturnUrl)) {
return Redirect(model.ReturnUrl);
} else if (string.IsNullOrEmpty(companyName)) {
return RedirectToAction("SelectCompany");
} else {
return RedirectToAction("Index", "Home", new { #company = companyName });
}
}
#endregion
#region Change Password
[Authorize]
public ActionResult ChangePassword() {
var model = new ChangePasswordModel();
return View(model);
}
[Authorize]
[HttpPost]
public ActionResult ChangePassword(ChangePasswordModel model) {
if (!ModelState.IsValid) {
return View(model);
}
using (var context = this.CreateAuditContext()) {
var user = this.GetCurrentUser(context);
if (model.NewPassword != model.ConfirmNewPassword) {
ModelState.AddModelError("ConfirmNewPassword",
"New password and password confirmation do not match");
return View(model);
}
if (hashUtility.VerifyHashString(model.CurrentPassword, user.Password, user.Salt)) {
string passwordHash;
string salt;
hashUtility.GetHashAndSaltString(model.NewPassword, out passwordHash, out salt);
user.Password = passwordHash;
user.Salt = salt;
context.SubmitChanges();
this.SetMessage(Models.MessageType.Success,
"Password has been successfully changed for this account");
} else {
this.SetMessage(Models.MessageType.Error,
"Incorrect password provided for this account, please verify and try again.");
return View(model);
}
context.CompleteTransaction();
}
return RedirectToAction("ChangePassword");
}
#endregion
#region Unauthorised
public ActionResult Unauthorised() {
this.SetTitle("Unauthorised Access");
return View();
}
#endregion
#region Logout
[Authorize]
public ActionResult Logout() {
FormsAuthentication.SignOut();
return RedirectToAction("Login");
}
#endregion
}
}
unauthorized access view
<h2>
Unauthorised Access</h2>
<p>
This user account does not have the authorisation to access this area of the system.</p>
#if (!Request.IsAuthenticated) {
#Html.ActionLink("Login", "Login", "Account", null, new { #class = "btn btn-primary" })
}
Has permission attribute:
/// <summary>
/// Attribute determining if a user has a particular permission
/// defined by its IPermissions profile
/// </summary>
public class HasPermissionAttribute : IsAuthorizedAttributeBase {
private Category category;
private AccessType? access;
public HasPermissionAttribute(Category category) {
this.category = category;
}
public HasPermissionAttribute(Category category, AccessType access) {
this.category = category;
this.access = access;
}
public override bool IsAuthorized(HttpContextBase httpContext) {
if (httpContext == null) {
throw new ArgumentNullException("httpContext");
}
if (!httpContext.User.Identity.IsAuthenticated) {
return false;
}
using (var context = DbConnectionFactory.CreateDataContext()) {
var userName = httpContext.User.Identity.Name;
var role = context.Users
.Where(u => u.Username == userName && !u.IsLocked)
.Select(u => u.Role).SingleOrDefault();
if (role == null)
return false;
IPermissions profile = UserRoleUtility.GetPermissionProfile(role);
if (access.HasValue)
return profile.HasPermission(category, access.Value);
else
return profile.HasPermission(category);
}
}
}
}
I don't know about IsAuthorizedAttributeBase attibute.
I am using AuthorizeAttribute and overriding HandleUnautherized method this in mvc 4.0 and it works like a charm.
*************Fitlers**********
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public sealed class FilterAuthAttribute:AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
HttpContext ctx = HttpContext.Current;
// If the browser session has expired...
if (ctx.Session["UserName"] == null)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
// For AJAX requests, we're overriding the returned JSON result with a simple string,
// indicating to the calling JavaScript code that a redirect should be performed.
filterContext.Result = new JsonResult { Data = "_Logon_" };
}
else
{
// For round-trip posts, we're forcing a redirect to Home/TimeoutRedirect/, which
// simply displays a temporary 5 second notification that they have timed out, and
// will, in turn, redirect to the logon page.
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary {
{ "Controller", "Home" },
{ "Action", "TimeoutRedirect" }
});
}
}
else if (filterContext.HttpContext.Request.IsAuthenticated)
{
// Otherwise the reason we got here was because the user didn't have access rights to the
// operation, and a 403 should be returned.
//filterContext.Result = new HttpStatusCodeResult(403);
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary {
{ "Controller", "Home" },
{ "Action", "Unauthorized" }
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}
regards
shaz
I am having issues retaining the passwordToken between my GET Controller and my View. I see that the token is passed and added to the model correctly within the GET Controller but as soon as the HTML.BeginForm starts in the View the model has a new instance and the previous model with the passwordToken is lost. I need the passwordToken to be retained in order to use WebSecurity.ResetPassword. Any suggestions on how this could be done?
My GET Controller:
[AllowAnonymous]
public ActionResult PasswordReset(string passwordToken)
{
// Token Validation
var usrID = WebSecurity.GetUserIdFromPasswordResetToken(passwordToken);
var usr = _dbManager.GetUserInformation(usrID);
if (usr == null)
{
//The link you are using is not valid anymore
return RedirectToAction("Error", "Account");
}
else
{
var model = new PasswordReset();
model.PasswordResetToken = passwordToken;
return View(model);
}
}
My View:
#model Project.Models.PasswordReset
#{
ViewBag.Title = "Password Reset";
}
<h2>Password Reset</h2>
<div class="form passwordreset-form">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<div class="input-form">
<div class="inputbox-label">
#Html.LabelFor(m => m.Password)
</div>
<div class="inputbox">
#Html.PasswordFor(m => m.Password)
</div>
<div class="inputbox-label">
#Html.LabelFor(m => m.ConfirmPassword)
</div>
<div class="inputbox">
#Html.PasswordFor(m => m.ConfirmPassword)
</div>
</div>
<div style="float:right;">
<input type="submit" value="Change Password" />
</div>
}
</div>
My POST Controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult PasswordReset(PasswordReset model)
{
//Attemp to change password
var passwordChangeConfirmation = WebSecurity.ResetPassword(model.PasswordResetToken, model.Password);
//Password has been changed
if(passwordChangeConfirmation == true)
{
return RedirectToAction("Index", "Home");
}
//Password change has failed
else
{
return RedirectToAction("Error", "Account");
}
}
I ended up adjusting the POST class to make it work.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult PasswordReset(PasswordReset model, string passwordToken)
{
//Attemp to change password
model.PasswordResetToken = passwordToken;
var passwordChangeConfirmation = WebSecurity.ResetPassword(model.PasswordResetToken, model.Password);
//Password has been changed
if (passwordChangeConfirmation == true)
{
return RedirectToAction("Index", "Home");
}
//Password change has failed
else
{
return RedirectToAction("Error", "Account");
}
}
add it into your form:
#Html.HiddenFor(m => m.PasswordResetToken);
You can use a hidden input on the form for the field (from your model) that you pass it.
#Html.HiddenFor(m => m.PasswordResetToken);
in output
<input type="hidden" name="PasswordResetToken"></input>
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);
}
}
}
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).