How can I implement a function that only the user named Admin can access?
Its important to do this without roles!
Like:
[Autohrize] => logged in users
But i want:
if username is like admin => you can access the page
Thank you
If i get you correct, you want to authorize user with user name. You can do that with custom authorize attribute.
public class UserNameAuthorizationAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
base.AuthorizeCore(httpContext);
dynamic user = HttpContext.Current.Session["user"];
return user.name == "Admin";
}
}
More detail can be found here
The different options are listed in this MSDN article. The option you want is the decorator "[Authorize(Users = "admin")]" for the SpecificUsersOnly method.
public class HomeController : Controller
{
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
[Authorize]
public ActionResult AuthenticatedUsers()
{
return View();
}
[Authorize(Roles = "Admin, Super User")]
public ActionResult AdministratorsOnly()
{
return View();
}
[Authorize(Users = "admin")]
public ActionResult SpecificUserOnly()
{
return View();
}
}
Related
Scenario
I have an Auth Controller, for authorizing user and admin credentials and registering new users. When a user is found to already exist, I want to reroute the controller to an overloaded action that I declare within the controller, passing a string as a Route Value to that action. However, at present, this doesn't appear to be working.
AuthController.cs
[HttpGet]
public IActionResult Register()
{
ViewData["Title"] = "Registration";
return View(new RegisterViewModel());
}
public IActionResult Register(string caption)
{
ViewData["Title"] = "Registration";
ViewBag.caption = caption;
return View(new RegisterViewModel());
}
[HttpPost]
public async Task<IActionResult> Register(RegisterViewModel vm)
{
if (!ModelState.IsValid)
return View(vm);
var user = new IdentityUser
{
UserName = vm.Email,
Email = vm.Email
};
var result = await _userManager.CreateAsync(user, "password");
if (result.Succeeded)
{
// !> Initial Registration!
await _signInManager.SignInAsync(user, false);
return RedirectToAction("Index", "Home");
}
return RedirectToAction("Register", "Auth", "This user is currently configured with a password");
}
Issue
Presently if I use the following Redirect:
return RedirectToAction("Register", "Auth", "This user is currently configured with a password");
it goes to the first, or this action:
public IActionResult Register()
{
ViewData["Title"] = "Registration";
return View(new RegisterViewModel());
}
rather than the second, or this action:
public IActionResult Register(string caption)
{
ViewData["Title"] = "Registration";
ViewBag.caption = caption;
return View(new RegisterViewModel());
}
Not quite sure whether I'm approaching this issue correctly. Any opinions or advice would surely be appreciated.
I think this is wrong:
return RedirectToAction("Register", "Auth", "This user is currently configured with a password");
You need to supply an object containing the parameters, not a string.
A string is only for defining an url fragment (https://en.wikipedia.org/wiki/Fragment_identifier).
See https://learn.microsoft.com/en-us/dotnet/api/system.web.mvc.controller.redirecttoaction?view=aspnet-mvc-5.2
Can you try:
return RedirectToAction("Register", "Auth", new { caption = "This user is currently configured with a password"});
You may try this below syntax ::
[RedirectToAction with parameter]
return RedirectToAction ("Action","controller",new {#id=id});
You could custom ActionMethodSelectorAttribute like below:
public class RequireRequestValueAttribute : ActionMethodSelectorAttribute
{
public RequireRequestValueAttribute(string valueName)
{
ValueName = valueName;
}
public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action)
{
bool contains = false;
contains = routeContext.HttpContext.Request.Query.ContainsKey(ValueName);
return contains;
}
public string ValueName { get; private set; }
}
For testing:
[HttpGet]
public IActionResult Register()
{
return View();
}
[HttpGet]
[RequireRequestValue("caption")]
public IActionResult Register(string caption)
{
ViewData["Title"] = "Registration";
ViewBag.caption = caption;
return View();
}
[HttpPost]
public async Task<IActionResult> Register()
{
return RedirectToAction("Register", "Account", new { caption = "This user is currently configured with a password" });
}
I'm creating ASP.NET MVC 4 Internet Application.
In that Application I created Login Page that any user can log in to, then I allowed to redirect user to different pages based on their role.
ASP.NET Identity is the membership system here.
This is my Login Controller method:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(model.UserName, model.Password);
if (user != null)
{
if (user.ConfirmedEmail == true)
{
await SignInAsync(user, model.RememberMe);
if (String.IsNullOrEmpty(returnUrl))
{
if (UserManager.IsInRole(user.Id, "HEC_Admin"))
{
return RedirectToAction("Index", "HEC");
}
//role Admin go to Admin page
if (UserManager.IsInRole(user.Id, "HEI_User"))
{
return RedirectToAction("Index", "HEI");
}
}
else
{
return RedirectToLocal(returnUrl);
}
}
else
{
ModelState.AddModelError("", "Confirm Email Address.");
}
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
This is HEI Controller Class:
public class HEIController : Controller
{
//
// GET: /HEI/
[Authorize(Roles = "HEI_User")]
public ActionResult Index()
{
return View();
}
}
This is my HEC Controller Class:
public class HECController : Controller
{
//
// GET: /HEC/
[Authorize(Roles = "HEC_Admin")]
public ActionResult Index()
{
return View();
}
}
when I remove [Authorize(Roles = "HEC_Admin")] above the index action in HECController class and when I remove [Authorize(Roles = "HEC_User")] above the index action in HEIController class this is working fine,
but then How restrict unauthorized access to these pages?
I had the same problem as you and I still don't know the reason why it happens. What I did was to create my own custom Authorization Attribute and check the Roles myself.
public class CustomAuthorizationAttribute : AuthorizeAttribute
{
public string IdentityRoles
{
get { return _identityRoles ?? String.Empty; }
set
{
_identityRoles = value;
_identityRolesSplit = SplitString(value);
}
}
private string _identityRoles;
private string[] _identityRolesSplit = new string[0];
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//do the base class AuthorizeCore first
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
return false;
}
if (_identityRolesSplit.Length > 0)
{
//get the UserManager
using(var um = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
var id = HttpContext.Current.User.Identity.GetUserId();
//get the Roles for this user
var roles = um.GetRoles(id);
//if the at least one of the Roles of the User is in the IdentityRoles list return true
if (_identityRolesSplit.Any(roles.Contains))
{
return true;
}
}
return false;
}
else
{
return true;
}
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
//if the user is not logged in use the deafult HandleUnauthorizedRequest and redirect to the login page
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
base.HandleUnauthorizedRequest(filterContext);
}
else
//if the user is logged in but is trying to access a page he/she doesn't have the right for show the access denied page
{
filterContext.Result = new RedirectResult("/AccessDenied");
}
}
protected static string[] SplitString(string original)
{
if (String.IsNullOrEmpty(original))
{
return new string[0];
}
var split = from piece in original.Split(',')
let trimmed = piece.Trim()
where !String.IsNullOrEmpty(trimmed)
select trimmed;
return split.ToArray();
}
}
I also added the HandleUnauthorizedRequest method to redirect to a appropriated page if the user has is logged in but has no access to this action or controller
To use it just do this:
[CustomAuthorization(IdentityRoles = "HEI_User")]
public ActionResult Index()
{
return View();
}
Hope it helps.
i'm having some problems with to pass value from UserProfile to #Viewbag to show in Index.cshtml.
Let's explain:
When i'm do a Register of new user or Login, i'm trying to pass UserType field from UserProfile in a viewbag.
UserType is a custom field that i create on UserProfile to validate if the user is a "Musico" or "Ouvinte"
After debug application, I see that viewbag is taking NULL value.
This is the code that i try to get value from UserProfile in Register and Login post method:
LOGIN POST METHOD
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid && WebSecurity.Login(model.UserName,
model.Password,
persistCookie: model.RememberMe))
{
var context = new UsersContext();
var username = User.Identity.Name;
var user = context.UserProfiles.SingleOrDefault(u => u.UserName == username);
var userType = user.UserType;
TempData["UserType"] = userType; //Taking UserType from User Profile
return RedirectToLocal(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
REGISTER POST METHOD
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
var context = new UsersContext();
var username = User.Identity.Name;
var user = context.UserProfiles
.SingleOrDefault(u => u.UserName == username);
var userType = user.UserType;
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new
{
UserType = model.UserType
});
WebSecurity.Login(model.UserName, model.Password);
// string currentUserType = u.UserType;
TempData["UserType"] = userType;//Get the userType to validate on _Layout
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
return View(model);
}
Calling viewbag in part of Index page
<p>
#if (Request.IsAuthenticated && ViewBag.UserType.Equals("Musico"))
{
<span>musico</span>
}
else if (Request.IsAuthenticated && ViewBag.UserType.Equals("Ouvinte"))
{
<span>ouvinte</span>
} else{
<span>teste</span>
}
</p>
HomeController
public ActionResult Index()
{
ViewBag.UserType = TempData["UserType"];
return View();
}
See this article for a good explanation, When to use ViewBag, ViewData, or TempData.
.. once the controller redirects, the ViewBag and ViewData will contain null values. If you inspect the TempData object with debugging tools after the redirect you'll see that it is fully populated.
Do this instead:
TempData["UserType"] = userType;
Change your view accordingly i.e.
#{var tempUserType = TempData["UserType"]} // in the top
And then use it as you would with the ViewBag
The ViewBag is lost because of the redirect.
An easy solution would be to use TempData, which only remains valid after one extra request. After that, it is normally gone, there is however a Keep method.
From MSDN:
However, the data in a TempDataDictionary object persists only from
one request to the next, unless you mark one or more keys for
retention by using the Keep method. If a key is marked for retention,
the key is retained for the next request.
Example:
[Authorize]
public class AccountController : Controller
{
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// do stuff
TempData["UserType"] = userType;
return RedirectToAction("Index", "Home");
}
// something went wrong, return view
return View(model);
}
}
[Authorize]
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.UserType = TempData["UserType"];
return View();
}
}
How can I create a custom AuthorizeAttribute that specifies a message in the form of a string parameter and then passes that along to the login page?
For example, ideally it would be cool to do this:
[Authorize(Message = "Access to the blah blah function requires login. Please login or create an account")]
public ActionResult SomeAction()
{
return View();
}
Then, in the Login action, I could do something like this:
public ActionResult Login(string message = "")
{
ViewData.Message = message;
return View();
}
And finally in the view I can do this:
#if (!String.IsNullOrEmpty(ViewData.Message))
{
<div class="message">#ViewData.Message</div>
}
<form> blah blah </form>
Basically I want to pass a custom message to the login page so I can display a message specific to what the user is trying to access at that particular time.
You can try something like this:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public string Message { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
var result = new ViewResult();
result.ViewName = "Login.cshtml"; //this can be a property you don't have to hard code it
result.MasterName = "_Layout.cshtml"; //this can also be a property
result.ViewBag.Message = this.Message;
filterContext.Result = result;
}
Usage:
[CustomAuthorize(Message = "You are not authorized.")]
public ActionResult Index()
{
return View();
}
web.config
<authentication mode="Forms">
<forms name="SqlAuthCookie"
loginUrl="~/Account/LogOnYouHavenotRight"
timeout="2880" />
</authentication>
Controller:
public ActionResult LogOn()
{
return View();
}
public ActionResult LogOnYouHavenotRight()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
}
In both Views:
Html.BeginForm("LogOn", "Account" )
I've recently created an ASP.NET MVC 2 application, which works perfectly in the development environment. However, when I deploy it to the server (123-reg Premium Hosting), I can access all of the expected areas - except the Account controller (www.host.info/Account). This then attempts to redirect to the Error.aspx page (www.host.info/Shared/Error.aspx) which it cannot find. I've checked that all of the views have been published, and they're all in the correct place.
It seems bizarre that two other controllers can be accessed with no problems, whereas the Account controller cannot be found. I have since renamed the AccountController to SecureController, and all of the dependencies, to no avail.
The problem with not being able to find the Error.aspx page also occurs on the development environment.
Any ideas would be greatly appreciated.
Thanks,
Chris
1) Can you check the DLL that was published to make sure that type exists in the assembly? Are any special modifiers applied to the Account controller compared to the other controllers (such as specific attributes, base classes, additional code)?
2) Can you verify what HttpMethod you are using to request the page? I'm assuming just a normal GET, but it may be coming in as a different verb causing you not to find your action method.
3) Are you using any custom routing, or just the standard {controller}/{action}/{id} setup?
The version of IIS on the server is 7.0, of which I have no control over.
The account controller code all works perfectly on the development environment, and the code is as follows:
[HandleError]
public class SecureController : Controller
{
private UserManager manager;
public IFormsAuthenticationService FormsService { get; set; }
public IMembershipService MembershipService { get; set; }
protected override void Initialize(RequestContext requestContext)
{
if (FormsService == null) { FormsService = new FormsAuthenticationService(); }
if (MembershipService == null) { MembershipService = new AccountMembershipService(); }
base.Initialize(requestContext);
}
// Lazy man's Dependency Injection for now, use Ninject later!
public SecureController(UserManager mgr) { manager = mgr; }
public SecureController() : this(new UserManager(new PortfolioDataDataContext())) { }
// **************************************
// URL: /Account/LogOn
// **************************************
public ActionResult LogOn()
{
return View();
}
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
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);
}
// **************************************
// URL: /Account/LogOff
// **************************************
public ActionResult LogOff()
{
FormsService.SignOut();
return RedirectToAction("Index", "Home");
}
// **************************************
// URL: /Account/Register
// **************************************
public ActionResult Register()
{
ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
return View();
}
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
MembershipCreateStatus createStatus = manager.CreateUser(model.UserName, model.Password, model.Email, model.FullName);
if (createStatus == MembershipCreateStatus.Success)
{
FormsService.SignIn(model.UserName, false /* createPersistentCookie */);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", AccountValidation.ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
return View(model);
}
// **************************************
// URL: /Account/ChangePassword
// **************************************
[Authorize]
public ActionResult ChangePassword()
{
ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
return View();
}
[Authorize]
[HttpPost]
public ActionResult ChangePassword(ChangePasswordModel model)
{
if (ModelState.IsValid)
{
if (MembershipService.ChangePassword(User.Identity.Name, model.OldPassword, model.NewPassword))
{
return RedirectToAction("ChangePasswordSuccess");
}
else
{
ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
}
}
// If we got this far, something failed, redisplay form
ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
return View(model);
}
// **************************************
// URL: /Account/ChangePasswordSuccess
// **************************************
public ActionResult ChangePasswordSuccess()
{
return View();
}
}