Authorize as Roles = "Admin" during login - asp.net-mvc

First of all i am new to MVC user authentication system. Code bellow is working fine for authenticate normal users but i wanted to log all user as per under MVC role based system. So admin user can only see admin controller and normal user cant see admin controller. I already made it on my admin controller i have added "[Authorize(Roles = "Admin")]" and i am also redirecting correctly to specific controller during login filter inside login controller. Now my issue is: How can i tell MVC "[Authorize(Roles = "Admin")]" is only accessed who has admin role? I mean how can i assign a user as admin from my login controller bellow? Ask any question if may have
Administrator Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Blexz.Controllers
{
[Authorize(Roles = "Admin")]
public class AdministratorController : Controller
{
// GET: Administrator
public ActionResult Index()
{
return View();
}
}
}
Login Controller:
//Login post
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(UserLogin login, string ReturnUrl="")
{
string Message = "";
using (BlexzWebDbEntities db = new BlexzWebDbEntities())
{
var v = db.Users.Where(x => x.Email == login.Email && x.IsEmailVerified == true).FirstOrDefault();
int RoleId = db.Users.Where(x => x.Email == login.Email).Select(x => x.RoleId).FirstOrDefault();
string RoleTypeName = db.Roles.Where(x => x.RoleId == RoleId).Select(x => x.RoleType).FirstOrDefault();
if (v != null)
{
if (string.Compare(Crypto.Hash(login.Password), v.PasswordHash) == 0)
{
int timeOut = login.RememberMe ? 43800 : 100; // 43800 == 1 month
var ticket = new FormsAuthenticationTicket(login.Email, login.RememberMe, timeOut);
string encrypted = FormsAuthentication.Encrypt(ticket);
var cookie = new System.Web.HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
cookie.Expires = DateTime.Now.AddMinutes(timeOut);
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
if (Url.IsLocalUrl(ReturnUrl))
{
return Redirect(ReturnUrl);
}
else if (RoleTypeName == "Admin")
{
return RedirectToAction("Index", "Administrator");
}
else
{
return RedirectToAction("User", "Home");
}
}
else
{
Message = "Invalid Credential Provided";
}
}
else
{
Message = "Invalid Credential Provided";
}
}
ViewBag.Message = Message;
return View();
}

Remove FirstOrDefault from RoleTypeName selection and change it as
string[] RoleTypeName = db.Roles.Where(x => x.RoleId == RoleId).Select(x => x.RoleType);
and change the checking as
if (Url.IsLocalUrl(ReturnUrl))
{
return Redirect(ReturnUrl);
}
else if (RoleTypeName.Contains("Admin"))
{
return RedirectToAction("Index", "Administrator");
}
else
{
return RedirectToAction("User", "Home");
}
Change your ticket as shown below
var ticket = new FormsAuthenticationTicket(
version: 1,
name: UserName,
issueDate: DateTime.Now,
expiration: DateTime.Now.AddSeconds(httpContext.Session.Timeout),
isPersistent: false,
userData: String.Join(",", RoleTypeName));
and After that in global.asax you would do something like this:
public override void Init()
{
base.AuthenticateRequest += OnAuthenticateRequest;
}
private void OnAuthenticateRequest(object sender, EventArgs eventArgs)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
var decodedTicket = FormsAuthentication.Decrypt(cookie.Value);
var roles = decodedTicket.UserData.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries);
var principal = new GenericPrincipal(HttpContext.Current.User.Identity, roles);
HttpContext.Current.User = principal;
}
}

Related

Making Sessions in MVC 6 Controller(with views, using Entity Framework)

I'm attempting to create a session in my UserAccountsController
using System.Linq;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Data.Entity;
using POPPELWebsite.Models;
namespace POPPELWebsite.Controllers
{
public class UserAccountController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Register()
{
return View();
}
[HttpPost]
public ActionResult Register(UserAccount account)
{
if (ModelState.IsValid)
{
using (OurDbContext db = new OurDbContext())
{
db.userAccount.Add(account);
db.SaveChanges();
}
ModelState.Clear();
ViewBag.Message = account.FirstName + " " + account.LastName + " successfully registered.";
}
return View();
}
//Login
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(UserAccount user)
{
using (OurDbContext db = new OurDbContext())
{
var usr = db.userAccount.Single(u => u.Email == user.Email && u.Password == user.Password);
if (usr != null)
{
Session["UserID"] = usr.UserID.ToString;
}
}
}
}
}
I get an error saying
the name Session does not exist in the current context.
I need to do this part to complete a registration and login tutorial for mvc
The Session property does not exist in the Controller class in MVC 6, instead use HttpContext.Session to access the session property.
Ex:
// get values
string strValue = HttpContext.Session.GetString("StringKey");
int intValue = HttpContext.Session.GetInt32("IntKey");
byte[] byteArrayValue = HttpContext.Session.Get("ByteArrayKey");
// set values
HttpContext.Session.Set("ByteArrayKey", byteArrayValue);
HttpContext.Session.SetInt32("IntKey", intValue);
HttpContext.Session.SetString("StringKey", strValue);
Try this.
public ActionResult Login(User users)
{
if (ModelState.IsValid)
{
using (DataContext db = new DataContext())
{
var obj = db.Users.Where(u => u.Username.Equals(users.Username) && u.Password.Equals(users.Password)).FirstOrDefault();
if(obj !=null)
{
System.Web.HttpContext context = System.Web.HttpContext.Current;
context.Session["UserId"] = obj.UserId.ToString();
context.Session["Username"] = obj.Username.ToString();
return RedirectToAction("Dashboard");
}
}
}
return View(users);
}

Authorize Attribute with Roles

I want to implement my custom authorization, I wonder what is wrong with my code even I got the user credentials correctly it still redirects me to my Login Method, please see the code below
Edit: I have successfully implemented the Authorize Attribute with Roles, for future readers please see code below
Login Controller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login (AdminViewModels.Login viewModel, string returnURL)
{
if (!ModelState.IsValid)
{
return View(viewModel);
}
PasswordHasher passwordVerify = new PasswordHasher();
var query = (from acc in db.accounts.Where(x => x.username == viewModel.Username)
select new { acc.username, acc.password}).FirstOrDefault();
if (query != null)
{
if (ModelState.IsValid)
{
var result = passwordVerify.VerifyHashedPassword(query.password, viewModel.Password);
switch (result)
{
case PasswordVerificationResult.Success:
//set forms ticket to be use in global.asax
SetupFormsAuthTicket(viewModel.Username, viewModel.rememeberMe);
return RedirectToLocal(returnURL);
case PasswordVerificationResult.Failed:
ModelState.AddModelError("", "Wrong Username or Password");
return View(viewModel);
}
}
}
return View(viewModel);
}
Forms Auth Ticket
private account SetupFormsAuthTicket(string userName, bool persistanceFlag)
{
account user = new account();
var userId = user.id;
var userData = userId.ToString(CultureInfo.InvariantCulture);
var authTicket = new FormsAuthenticationTicket(1, //version
userName, // user name
DateTime.Now, //creation
DateTime.Now.AddMinutes(20), //Expiration
persistanceFlag, //Persistent
userData);
var encTicket = FormsAuthentication.Encrypt(authTicket);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
return user;
}
Global.asax
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//take out user name from cookies
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string[] roles = null;
trainingEntities db = new trainingEntities();
//query database to get user roles
var query = (from acc in db.account_roles where acc.account.username == username select acc.role.role_name).ToArray();
roles = query;
//Let us set the Pricipal with our user specific details
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles);
}
catch (Exception)
{
//somehting went wrong
}
}
}
}
Now you can use [Authorize(Roles = "Admin")]
to any action method or on top of controller
I have successfully implemented the Authorize Attribute with Roles, for future readers please see code below.
Login Controller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login (AdminViewModels.Login viewModel, string returnURL)
{
if (!ModelState.IsValid)
{
return View(viewModel);
}
PasswordHasher passwordVerify = new PasswordHasher();
var query = (from acc in db.accounts.Where(x => x.username == viewModel.Username)
select new { acc.username, acc.password}).FirstOrDefault();
if (query != null)
{
if (ModelState.IsValid)
{
var result = passwordVerify.VerifyHashedPassword(query.password, viewModel.Password);
switch (result)
{
case PasswordVerificationResult.Success:
//set forms ticket to be use in global.asax
SetupFormsAuthTicket(viewModel.Username, viewModel.rememeberMe);
return RedirectToLocal(returnURL);
case PasswordVerificationResult.Failed:
ModelState.AddModelError("", "Wrong Username or Password");
return View(viewModel);
}
}
}
return View(viewModel);
}
FormsAuthTicket
private account SetupFormsAuthTicket(string userName, bool persistanceFlag)
{
account user = new account();
var userId = user.id;
var userData = userId.ToString(CultureInfo.InvariantCulture);
var authTicket = new FormsAuthenticationTicket(1, //version
userName, // user name
DateTime.Now, //creation
DateTime.Now.AddMinutes(20), //Expiration
persistanceFlag, //Persistent
userData);
var encTicket = FormsAuthentication.Encrypt(authTicket);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
return user;
}
Global.asax
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//take out user name from cookies
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string[] roles = null;
trainingEntities db = new trainingEntities();
//query database to get user roles
var query = (from acc in db.account_roles where acc.account.username == username select acc.role.role_name).ToArray();
roles = query;
//Let us set the Pricipal with our user specific details
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles);
}
catch (Exception)
{
//somehting went wrong
}
}
}
}
Now you can use [Authorize(Roles = "Admin")]
to any action method or on top of controller
as I see in ControllerLogin attribute it is now being applied in a variable, when it should be applied to a method or a class
[CustomAuthorization(UserRole="Admin")]
// GET: Manage
private trainingEntities db = new trainingEntities();
public ActionResult Index()
{
return View();
}
Private trainingEntities dB = new TrainingEntities();
[CustomAuthorization(UserRole="Admin")]
Public ActionResult Index()
{
//yourcode
}

I am not able to get the User.Identity.Name after redirected from controller in Mvc

In the 1st example:-
i am assigning User.Identity.Name value to the variable id. i am able to get the value after that i am Redirecting to some other view here i am using Redirect(ReturnUrl) now i am able to get the User.Identity.Name value in the other controller(Redirected view) also
But in the 2nd example :-
i am assigning User.Identity.Name value to the variable id i am able to get the value after that i am Redirecting to some other view here i am using return Redirect(ReturnUrl);when i am using return Redirect(ReturnUrl);am not able to get the User.Identity.Name value in the Redirected url
Example 1:-
public ActionResult SignIn(string ReturnUrl)
{
if (ReturnUrl == "/" || string.IsNullOrEmpty(ReturnUrl))
{
ReturnUrl = "/Dashboard";
}
var id=HttpContext.Current.User.Identity.Name;
Response.Redirect(ReturnUrl);
return View();
}
Example 2:-
public ActionResult SignIn(string ReturnUrl)
{
if (ReturnUrl == "/" || string.IsNullOrEmpty(ReturnUrl))
{
ReturnUrl = "/Dashboard";
}
var id=HttpContext.Current.User.Identity.Name;
return Redirect(ReturnUrl);
}
My Controller:- In this function if i am return Redirect(ReturnUrl); i am not able to get the User.Identity.Name value in CompanyRequired filter if i am using Response.Redirect(ReturnUrl); return View(); then able to get the User.Identity.Name value in CompanyRequired filter but i have to use return Redirect(ReturnUrl);
[HttpPost]
public async Task<ActionResult> SignInCallback()
{
var token = Request.Form["id_token"];
var state = Request.Form["state"];
var claims = await ValidateIdentityTokenAsync(token, state);
string ReturnUrl = state.Substring(state.IndexOf('?') + 1);
var id = new ClaimsIdentity(claims, "Cookies");
Request.GetOwinContext().Authentication.SignIn(id);
if (ReturnUrl == "/" || string.IsNullOrEmpty(ReturnUrl))
{
ReturnUrl = "/Dashboard";
}
var Id = User.Identity.Name;
return Redirect(ReturnUrl);
}
View:- Here i control will go to the CompanyRequired filter there i need a User.Identity.Name value in that i am getting value null
[Authorize,CompanyRequired]
public class DashBoardController : BaseController
{
public ActionResult Index()
{
return View();
}
}
CompanyRequired Filter:-
public class CompanyRequiredAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var coCookie = filterContext.HttpContext.Request.Cookies["CoId"];
if (coCookie == null)
{
var Id= HttpContext.Current.User.Identity.Name.Int(); **//here i need to get the value but i am getting null value**
IdNmList cos = new EmployeeDAL().GetCompany(Id);
if (cos.Count == 0)
{
filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary
{
{ "controller" , "Company"},
{ "action" , "Add"}
});
}
else if (cos.Count == 1)
{
filterContext.HttpContext.Response.Cookies.Add(new HttpCookie("CoId", cos[0].Id.ToString()));
}
else
{
filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary
{
{ "controller", "Company" },
{ "action", "Select" },
{ "ReturnUrl", filterContext.HttpContext.Request.RawUrl }
});
}
}
base.OnActionExecuting(filterContext);
}
}

Issue with Request.IsAuthenticated after Login page mvc asp.net

I am having an issue with checking the authentication when a user logs in to my site. So I have a login page (Login.cshtml), that of course a user would login from. From there the user would be sent to an index page. My issue is that when i hit this
#if (Request.IsAuthenticated)
{
<strong>#Html.Encode(User.Identity.Name)</strong>
}
else
{
<strong>Something went wrong</strong>
}
it fails into the else statement and writes something went wrong. Any advice on how to combat this error would be greatly appreciated. Thank you in advance.
Index.cshtml:
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
#if (Request.IsAuthenticated)
{
<strong>#Html.Encode(User.Identity.Name)</strong>
}
else
{
<strong>Something went wrong</strong>
}
My UserContoller(has all the methods for the login):
public ActionResult Index()
{
var user = db.User.Include(u => u.UserName);
var loggedInUser = User.Identity.Name;
return View();
}
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(Models.User user)
{
if (ModelState.IsValid)
{
if (isValid(user.UserName, user.Password))
{
FormsAuthentication.SetAuthCookie(user.UserName, false);
return RedirectToAction("Index", "User");
}
else
{
ModelState.AddModelError("", "User Name or Password is incorrect");
}
}
return View(user);
}
private bool isValid(string UserName, string Password)
{
bool isValid = false;
//var user = db.User.SingleOrDefault(u => u.UserName == UserName);
var user = db.User.Where(u => u.UserName == UserName).FirstOrDefault();
var pass = db.User.Where(u => u.Password == Password).FirstOrDefault();
if (user != null && pass != null)
{
isValid = true;
}
return isValid;
}

Authorize Attribute Not Working with Roles MVC C#

I'm modifying a system written in c# MVC at the moment.
I've just built in an extra bit of functionality in the Administrator area that allows the administrator create a user account that has limited administrator functionality. I've put the following over each of the controllers for the new functionality:
[Authorize(Roles = "Administrator")]
However, if I log in using limited administrator account, and navigate to this page, it lets me through.
I'm stumped because I appear to be doing this the right way but I'm also fairly new to MVC, is there anything else I can check? I haven't changed anything in the web.config file so that should be ok.
I know there's limited information above, not looking for a ready-made solution, more advice on what I can check to correct the issue.
thanks
EDIT:
This is how the new role/account was created. Go easy too, this is a first ditch attempt, there's not much validation.
[Authorize(Roles = "Administrator")]
[HttpPost]
public ActionResult AddSalesManager(App.Web.Areas.Administrator.Models.SalesManager model, FormCollection formValues)
{
if (formValues["Cancel"] != null)
{
return RedirectToAction("Index");
}
if (!string.Equals(model.password, model.confirmpassword))
{
ModelState.AddModelError("password", "Password and Confirmation must match");
}
if (ModelState.IsValid)
{
using (ModelContainer ctn = new ModelContainer())
{
// First, create the user account inside the ASP.Net membership system.
//
Membership.ApplicationName = "App";
Roles.ApplicationName = "App";
if (!Roles.RoleExists("LimitedAdmin"))
Roles.CreateRole("LimitedAdmin");
// MembershipCreateStatus createStatus = MembershipService.CreateUser(model.email, model.password, model.email);
if (Membership.GetUser(model.email) == null)
{
Membership.CreateUser(model.email, model.password);
Roles.AddUserToRole(model.email, "LimitedAdmin");
}
}
}
return RedirectToAction("Index");
}
Role attribute
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class PermissionsAttribute : ActionFilterAttribute
{
private readonly PermissionsType required;
public PermissionsAttribute()
{
}
public PermissionsAttribute(PermissionsType required)
{
this.required = required;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Log("OnActionExecuting", filterContext.RouteData);
HttpSessionStateBase session = filterContext.HttpContext.Session;
Controller controller = filterContext.Controller as Controller;
//This is uesd to redirect to same controller but differnect action
// controller.HttpContext.Response.Redirect("./Login");
var rjasthan = filterContext;
var URK = filterContext.HttpContext.Request.RawUrl;
if (session["UserPermissions"] != null)
{
if (!CheckPermissions((UserPermission)session["UserPermissions"]))
{
// this is used to signout from sesssion
// filterContext.HttpContext.GetOwinContext().Authentication.SignOut();
filterContext.Controller.TempData["AuthenticationMessages"] = "You are not authorized to access";
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary{
{ "controller", "Home" },{ "action", "UnAuthorizeAccess" }});
}
}
base.OnActionExecuting(filterContext);
}
protected bool CheckPermissions(UserPermission model)
{
bool result = false;
if (this.required == (PermissionsType.Add))
{
if (model.AddRight)
result = true;
}
else if (this.required == (PermissionsType.View))
{
if (model.ViewRight)
result = true;
}
else if (this.required == (PermissionsType.Edit))
{
if (model.EditRight)
result = true;
}
else if (this.required == (PermissionsType.Delete))
{
if (model.DeleteRight)
result = true;
}
else if (this.required == (PermissionsType.View | PermissionsType.Edit))
{
if (model.ViewRight && model.EditRight)
{
result = true;
}
}
else if (this.required == (PermissionsType.Add | PermissionsType.Edit))
{
if (model.AddRight && model.EditRight)
{
result = true;
}
}
return result;
}
private void Log(string methodName, RouteData routeData)
{
var controllerName = routeData.Values["controller"];
var actionName = routeData.Values["action"];
var message = String.Format("{0} controller:{1} action:{2}", methodName, controllerName, actionName);
Debug.WriteLine(message, "Action Filter Log");
}
}
[Flags]
public enum PermissionsType
{
View = (1 << 0),
Add = (1 << 1),
Edit = (1 << 2),
Delete = (1 << 3),
Admin = (View | Add | Edit | Delete)
}
[Permissions(PermissionsType.Add)]
public ActionResult Register()
{
return this.AjaxableView();
}
What do you expect from this code?
With this attribute you gain all users in the administrator role the right to execute this controller action no matter how limited the account is.

Resources