This is the code I used for membership in Global.asax
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string roles = string.Empty;
IUserService _userService= new UserService();
UserViewModel user = _userService.SelectUserByUserName(username).UserList.FirstOrDefault();
roles = user.role;
//let us extract the roles from our own custom cookie
//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.Split(','));
}
catch (Exception)
{
//somehting went wrong
}
}
}
}
I'm trying to redirect the user for different view if his Role is "Manager",this is what I tried to get the user roles in the controller but It returns an empty list :
[Authorize(Roles = "admin, manager")]
public ActionResult Index()
{
string[] rolesArray;
rolesArray = Roles.GetAllRoles();// returns an empty array
foreach(var item in rolesArray){
if(item == "manager"){
return RedirectToAction("index", "Manager");
}
}
return View();
}
You should be able to call .IsInRole()
if (User.IsInRole("manager"))
{
return RedirectToAction("index", "Manager");
}
Related
I am new to backend programming with C# MVC, and I created a login system which works.
public ActionResult Login(LogingInViewModel Login)
{
if (ModelState.IsValid)
{
User user = _context.users.FirstOrDefault(u => u.Email == Login.Email);
if (user != null)
{
if (user.Password== Crypto.SHA256(Login.Password))
{
user.Token = Guid.NewGuid().ToString();
_context.SaveChanges();
HttpCookie tokenCookie = new HttpCookie("token")
{
Value=user.Token,
HttpOnly=true
};
tokenCookie.Expires = DateTime.Now.AddDays(10);
Response.Cookies.Add(tokenCookie);
return RedirectToAction("index","Home",user);
}
}
ModelState.AddModelError("CustomError", "Wrong Email or Password");
}
LoginViewModel model1 = new LoginViewModel
{
Login = Login
};
return View("~/Views/Login/Index.cshtml", model1);
}
but I have no idea how I can use this object in all my other pages/controllers or even Shared/Layout to display username and profile picture up top.
I looked up online and tried some solutions, but they didn't work like
#if (Model != null) { <span>#Model.Fullname</span>}
else { <span>Log in</span> }
and of course since I can not send the object it is null.
Currently, I am working on a web application, based on the roles we have to display the controls in the UI. Roles are stored in the DB, whenever the user logs in, by fetching the user Id, I will hit the DB and get the user role and store it in the cookie. So, for the next request, I will fetch the user role from the User.IsInRole() and proceed with the logic same will happens in the view. This entire thing is working fine with the single server but when it comes to load balancer, this behaving weirdly and intermittently it's giving issue, as User.IsInRole() is returning false sometime.
The code in my controller:
public ActionResult IsValidUser(string userName)
{
try
{
if (HttpContext!=null&& HttpContext.Request.Headers["username"] != null)
{
userName = HttpContext.Request.Headers["username"];
}
//Get the roles by sending the user name
userRole = _processor.GetUserRole(userName);
UserViewModel user = new UserViewModel()
{
UserName = userName,
Role = userRole
};
if (!string.IsNullOrEmpty(user.Role))
{
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, user.UserName, DateTime.Now, DateTime.Now.AddMinutes(2880), true, user.Role, FormsAuthentication.FormsCookiePath);
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
if (ticket.IsPersistent)
{
cookie.Expires = ticket.Expiration;
}
if(Response!=null)
Response.Cookies.Add(cookie);
if (!string.IsNullOrEmpty(Request.Form["ReturnUrl"]))
{
return View("Error");
}
else
{
return RedirectToAction("Index");
}
}
else
{
return View("Error")
}
}
else
return RedirectToAction("Search");
}
catch (Exception ex)
{
return View("Error);
}
}
The code in Global.asax.cs
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity is FormsIdentity)
{
FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);
}
}
}
}
the code in my controller to do the logic:
public FileContentResult ViewAttachment(string attachmentName, int attachmentId)
{
if (ConfigurationManager.AppSettings["Environment"] != Constants.ProductionEnvironment ||
(User.IsInRole(Constants.Administrator) || User.IsInRole(Constants.Contributor) || User.IsInRole(Constants.Member)))
{
//Logic here
return File(bytes, mimeType);
}
else
{
_logger.WriteInformation("Not authorized");
return File(bytes, mimeType);
}
}
I am not sure what mistake is there but this is not working in load balancer sometimes it is showing "User is not authorized" but in actual user is authorized. Is it because of cookies or load balancer? Any help would be appreciated. Thanks in advance.
I am using MVC form base custom authentication using SQL database. I've Column with CustomerRole name.
I am checking Authorization as per following:
TestController.CS
[Authorize]
public ActionResult Index()
{
return View();
}
[Authorize(Roles="admin")]
public ActionResult AdminPage()
{
return View();
}
AccountController.cs
[HttpPost]
public ActionResult Login(UserModel model, string returnUrl)
{
// Lets first check if the Model is valid or not
if (ModelState.IsValid)
{
using (userDbEntities entities = new userDbEntities())
{
string username = model.username;
string password = model.password;
// Now if our password was enctypted or hashed we would have done the
// same operation on the user entered password here, But for now
// since the password is in plain text lets just authenticate directly
bool userValid = entities.Tbl_UserMast.Any(user => user.UserName == username && user.UserPassword == password);
// User found in the database
if (userValid)
{
FormsAuthentication.SetAuthCookie(username, false);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
So when I go AdminPage Action. It shows me I am not Authorized.
If I change my column name as Roles, it is working. But I am not allowed to change column name. Is there any other alternative, where I can use Authorization with same column name
You should Try Custom Authentication Filer
Try this:
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string roles = string.Empty;
using (userDbEntities entities = new userDbEntities())
{
var user = entities.Users.SingleOrDefault(u => u.username == UserName);
roles = user.UserRole;
}
//let us extract the roles from our own custom cookie
//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.Split(';'));
}
catch (Exception)
{
//somehting went wrong
}
}
}
}
I have a custom ActionFilterAttribute that makes sure a value in the Session matches a value in the database. If the values don't match, it redirects the user to the Login action on the AccountController.
public class CheckSessionAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), false).Any())
{
// If the action allows Anonymous users, no need to check the session
return;
}
var session = filterContext.RequestContext.HttpContext.Session;
var userName = filterContext.RequestContext.HttpContext.User.Identity.Name;
var userStore = new ApplicationUserStore(new IdentityDb());
var userManager = new ApplicationUserManager(userStore);
var user = userManager.FindByNameAsync(userName).Result;
if (userName == null || user == null || session == null || session["ActiveSessionId"] == null ||
session["ActiveSessionId"].ToString() != user.ActiveSessionId.ToString())
{
session.RemoveAll();
session.Clear();
session.Abandon();
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(new
{
action = "Login",
controller = "Account"
}
));
}
base.OnActionExecuting(filterContext);
}
}
[Authorize]
public class AccountController : Controller
{
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
SignOutAndKillSession();
ViewBag.ReturnUrl = returnUrl;
return View();
}
private void SignOutAndKillSession()
{
AuthenticationManager.SignOut();
Session.RemoveAll();
Session.Clear();
Session.Abandon();
}
}
When I try to login again after being redirected to the Login action, I get the following exception:
The provided anti-forgery token was meant for a different claims-based user than the current user
I set a breakpoint inside the Login action and can see that User.Identity.Name is still set to the user that is being logged out, before AND after the call SignOutAndKillSession(). I believe this is what's causing an incorrect AntiForgeryToken to be generated when the page renders.
Can someone help me find out how to clear the User Principal when logging out a user?
Thanks
For anyone that runs into this issue, I solved it by expiring the cookies created by MVC 5 inside the CheckSessionAttribute. I also changed the attribute from an ActionFilterAttribute to an IAuthorizationFilter Attribute
public class CheckSessionAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), false).Any())
{
// If the action allows Anonymous users, no need to check the session
return;
}
var session = filterContext.RequestContext.HttpContext.Session;
var userName = filterContext.RequestContext.HttpContext.User.Identity.Name;
var userStore = new ApplicationUserStore(new IdentityDb());
var userManager = new ApplicationUserManager(userStore);
var user = userManager.FindByNameAsync(userName).Result;
if (userName == null || user == null || session == null || session["ActiveSessionId"] == null ||
session["ActiveSessionId"].ToString() != user.ActiveSessionId.ToString())
{
session.RemoveAll();
session.Clear();
session.Abandon();
ExpireCookie("ASP.NET_SessionId", filterContext);
ExpireCookie("__RequestVerificationToken", filterContext);
ExpireCookie(".AspNet.ApplicationCookie", filterContext);
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(new
{
action = "Login",
controller = "Account"
}
));
}
return;
}
private void ExpireCookie(string name, AuthorizationContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.Cookies[name] != null)
{
filterContext.RequestContext.HttpContext.Response.Cookies[name].Value = string.Empty;
filterContext.RequestContext.HttpContext.Response.Cookies[name].Expires = DateTime.Now.AddMonths(-20);
}
}
}
I have my ASP.NET MVC 4 project and database (SQL Server 2008)
And I've created an entity framework model, with auto-generated models.
And in the database there is a table called Roles (2 fields, Id and name)
There are 3 roles: admin, moderator, user.
Plus Account controller:
public class AccountController : Controller
{
private korovin_idzEntities db = new korovin_idzEntities();
//
// GET: /Account/LogOn
public ActionResult LogOn()
{
return View();
}
//
// POST: /Account/LogOn
[HttpPost]
public ActionResult LogOn(LogOnModel model/*, string returnUrl*/)
{
if (ModelState.IsValid)
{
var user = db.Users.Where(x => x.username == model.UserName && x.password == model.Password).FirstOrDefault();
if (user != null)
{
user.isRemember = model.RememberMe;
db.SaveChanges();
ViewBag.UserName = model.UserName;
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
FormsAuthentication.RedirectFromLoginPage(model.UserName, false);
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
return View(model);
}
}
Where and how can i initialize roles in my asp.net mvc application? I've tried to check whether role exists and to initialize role by rolemanager in account controller, but i think it's not a good solution.
Is it possible to initialize roles in global.asax.cs?
I know that I should attach roles to user in log on function.
Thanks in advance :)
Here is my solution, I thought that there is some kind of a structure for storing a names of roles and there is needed to initialize this structure, but i was wrong, and after googling, I've found the solution:
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
var context = HttpContext.Current;
if (context.Request.IsAuthenticated)
{
string[] roles = LookupRolesForUser(context.User.Identity.Name);
var newUser = new GenericPrincipal(context.User.Identity, roles);
context.User = Thread.CurrentPrincipal = newUser;
}
}
#region helper
private string[] LookupRolesForUser(string userName)
{
string[] roles = new string[1];
CosmosMusic.Models.korovin_idzEntities db = new CosmosMusic.Models.korovin_idzEntities();
var roleId = db.Users.Where(x => x.username == userName).FirstOrDefault().id_role;
roles[0] = db.Role.Where(y => y.id_role == roleId).FirstOrDefault().name;
return roles;
}
#endregion