I have created a ASP.NET MVC core application. I just finished creating and logging in a user. Now I'm trying to figure out
1. how to have the user login info saved
2. how to require a user to be logged in to visit the rest of the the site.
For saving the user log info. I was going to use either Identity or Asp.Net.Session, but seeing has I cant find anything that shows how to require the user to be logged in to visit routes, I’m unsure which option would work best.
Could someone explain to me how to require authentication before accessing a route, and which of the saving login info works best with that method?
Current Login Example
public ActionResult Login(LoginModel model){
if (ModelState.IsValid){
SqlConnect test = new SqlConnect("Data Source=/home/andrew/database.db","Accounts");
var check = test.count(model.UserName,model.Password);
if(check){
// Found in database
return RedirectToAction("Index","Home");
}
}
// If we got this far, something failed, redisplay form
return RedirectToAction("Error","Home");
}
You shouldn't secure routes. When using placeholders (such as in the default route), it is possible that more than one route can reach an action method. These alternate paths are sure to be difficult (nearly impossible) to keep secure as your application changes over time.
So the best option is to secure the resources by preventing them from being served. Note that this is also the way security works in ASP.NET, so both ASP.NET and MVC hook into the same mechanism (IPrincipal and IIdentity) to control both authentication and authorization. ASP.NET Identity and older security frameworks from Microsoft all use this extension point to plug into MVC and ASP.NET.
In MVC, it is the AuthorizeAttribute that uses these interfaces to secure action methods. AuthorizeAttribute can be used in several ways:
On Action Methods
public class MyController
{
[Authorize(Roles = "Admin,SuperUser")]
public ActionResult Index()
{
return View();
{
}
On Controllers
[Authorize(Roles = "Admin,SuperUser")]
public class MyController
{
[AllowAnonymous] // All users have access
public ActionResult Index()
{
return View();
{
// Only authenticated users in Admin or SuperUser
// role have access
public ActionResult Contact()
{
return View();
{
// Only authenticated users in Admin or SuperUser
// role have access
public ActionResult About()
{
return View();
{
}
Globally
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new AuthorizeAttribute());
filters.Add(new HandleErrorAttribute());
}
}
This means that only authenticated users can access any action method in your application. You can also use roles here like filters.Add(new AuthorizeAttribute() { Roles = "Foo,Bar" });. And you can allow specific controllers/actions access to unauthenticated users with the AllowAnonymousAttribute.
You can also subclass AuthorizeAttribute if you have more complex business logic than just Users and Roles.
Related
I have a .NET Core 2 MVC project and I have a part of the website totally separated from the other one in my project. These both "parts" share the same set of users.
In one of the parts of the project I want users to be able to see the login page, but only users having specific role to be able to actually log in.
Currently I use the IsInRoleAsync method of ASP.NET Identity's user manager, but I am wondering if there is any better solution to this?
Thanks
You can use the Authorize attribute :
public class AccountController : Controller
{
[HttpGet]
public ActionResult Login()
{
// shows the login page
}
[HttpPost]
[Authorize(Roles = "Administrator")]
public ActionResult Login(LoginViewModel model)
{
// Process login
}
}
I think you can use your code like this:
[HttpPost]
public ActionResult Login(LoginViewModel model)
{
// Process login
// after he loged in
// Check if he is an admin, if not log out using :
await signInManager.SignOutAsync();
// then redirect to login page with a message
}
I hope this works for you.
In .Net MVC5, how would one add a request filter to prevent action calls based on role membership?
See this comment:
wouldn't it make more sense to use a request filter to prevent the
action call on the controller in the event that the current user did
not have the right role membership instead of trying to mix the auth
logic in to the business logic?
Thank you.
My best solution for this is using:
[AuthorizeAttribute]
You can place it as a normal attribute is used in c# mvc, like for ex:
[Authorize]
public ActionResult AuthenticatedUsers()
{
return View();
}
You can also use it in top of the controller like this:
[Authorize]
public class HomeController : Controller
{
}
And if you want it do be depedent on roles, you just simple give one parameter to this attribute like this:
[Authorize(Roles = "Admin, Super User")]
public ActionResult AdministratorsOnly()
{
return View();
}
[Authorize(Users = "Betty, Johnny")]
public ActionResult SpecificUserOnly()
{
return View();
}
Here is some more detailed information for your question which I'd suggest would help you alot.
Good luck!
I have an internal web app being built in ASP.NET 4. We are stuck with using an authentication API built by another team. If a user to the site is authenticated successfully for the site I would like to give them access to the entire site.
In ASP.NET WebForm days I just used to keep a custom User object in session. If that object was null I knew the user wasn't authenticated. Is there a similar but improved method for this in MVC. I don't want to have to build my own provider of the ASP.NET Membership model if possible. What is the simplest way of doing this?
You can use Forms Authentication in conjuction with Authorize attibute as follows,
To restrict access to a view :
Add the AuthorizeAttribute attribute to the action method declaration, as shown below,
[Authorize]
public ActionResult Index()
{
return View();
}
Configuring Forms Authentication in web.config
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
Login Post Action:
Set Authentication cookie if user is valid
[HttpPost]
public ActionResult Login(User model, string returnUrl)
{
//Validation code
if (userValid)
{
FormsAuthentication.SetAuthCookie(username, false);
}
}
Log off Action:
public ActionResult LogOff()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Home");
}
You probably want to have a custom authorization filter. Here's an example: Custom filters in MVC. You can then apply this filter globally on app start (using RegisterGlobalFilters).
public class LegacyAuthorize : AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (HttpContext.Current.Session["User"] == null)
base.HandleUnauthorizedRequest(actionContext);
}
}
Then in your global.asax you'd have something like this:
GlobalFilters.Filters.Add(new LegacyAuthorize());
You can try with something like this:
FormsAuthentication.SetAuthCookie(username, rememberMe);
to set the cookie for authenticated user, then just use the [Authorize] attribute on the Controller or Action that need authentication.
Try googling on the subject for further info, you will find a lot of stuff on authentication and authorization in MVC.
Everything you could do in forms you can do in MVC, just set the session variable in the controller login action.
Or you can do this:
In the login action add formsauthentication.setauthcookie("username")
After this any action with the [Authorize] keyword will allow the current user in.
You can do the Session Authentication by simply putting a session variable value when the login is successful. Eg
public ActionResult Index(Models.Login login)
{
if (ModelState.IsValid)
{
Dal.Login dLogin = new Dal.Login();
string result = dLogin.LoginUser(login);
if (result == "Success")
Session["AuthState"] = "Authenticated";
}
return View();
}
Now the trick is that you should have a common layout page of all the views to which you have to check for authentication. And in this layout page just do a razor check like this -
<body>
#if (Session["AuthState"] != "Authenticated")
{
Response.Redirect("~/login");
}
// other html
</body>
I have been using this method in my application admin panel.
I created a new controller called Dashboard and a View called Index which says, Hello Username.
In MVC, how can I make this only available to logged in users?
You can use the Authorize attribute:
[Authorize]
public ActionResult Index()
{
}
Assume like this is my SampleController action method
public ActionResult AdminView()
{
return View()
}
If want this controller method to be called if the logged in user belongs to admin role, otherwise this method call should be blocked and the user should get an some custom unauthorized access error page.
In my asp .net mvc web application, when the user logs in, I am storing the user role in a session as a string. And whenever there is a need to validate the user role, I compare the value stored in the session against a constant say "ADMIN_ROLE". But I am writing that piece of code to check for the user role in almost every controller action method and then either return an appropriate view for the user or an unauthorized access page view if the user role is restricted for the controller action method.
I googled and read that we can use something like this.
[Authorize(Roles="admin")]
public ActionResult AdminView()
{
return View()
}
But I am not sure how the Authorize and the Roles keyword works. How when putting Roles = "Admin", is going to help in checking my user role string stored in the session, or how I can redirect a user to unauthorized page, in case the role does not match the role tagged for the action method.
As per my thinking you need to code for authorization.
public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
private readonly RoleEnum[] _acceptedRoles;
public AuthorizeAttribute(params RoleEnum[] acceptedroles)
{
_acceptedRoles = acceptedroles;
}
public AuthorizeAttribute(params bool[] allowAll)
{
if (allowAll[0])
_acceptedRoles = new RoleEnum[] { RoleEnum.Admin, RoleEnum.user};
}
public void OnAuthorization(AuthorizationContext filterContext)
{
if (SessionHelper.UserInSession == null)//user not logged in
{
FormsAuthentication.SignOut();
filterContext.Result =
new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary {{ "controller", "Home" },
{ "action", "Index" },
{ "returnUrl", filterContext.HttpContext.Request.RawUrl } });//send the user to login page with return url
return;
}
if (!_acceptedRoles.Any(acceptedRole => SessionHelper.UserInSession.UserRoles.Any(currentRole => acceptedRole == currentRole.Role)))
//allow if any of the user roles is among accepted roles. Else redirect to login page
throw new UnauthorizedAccessException();
}
}
This is also work for return URL.
As per comments, if you are using custom authentication/authorization mechanism then you need to implement custom authorize attribute where you can put custom logic to check if user has admin role or not. Something like below:
public class CustomizedAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
//check for role in session variable "ADMIN_ROLE"
//if not valid user then set
filterContext.Result = new RedirectResult(URL)
}
}
There is a small nice explanation in this link:
http://weblogs.asp.net/jgalloway/archive/2011/04/28/looking-at-how-asp-net-mvc-authorize-interacts-with-asp-net-forms-authorization.aspx
as per this:
ASP.NET MVC includes an [Authorize] attribute, which when placed on any controller actions will forbid unauthorized access. The AuthorizeAttribute allows you to specify a list of roles or users.
You can also place the AuthorizeAttribute on a controller, in which case it will apply to all actions in the controller. Attempting to access an action secured by the AuthorizeAttribute when you're not logged in will take you to a standard LogOn screen, with a link to register if you don't already have an account.
How does the [Authorize] attribute redirect me to Log On?
The AuthorizeAttribute is an ActionFilter, which means that it can execute before the associated controller action. The AuthorizeAttribute performs its main work in the OnAuthorization method, which is a standard method defined in the IAuthorizationFilter interface. Checking the MVC source code, we can see that the underlying security check is really just looking at the underlying authentication information held by the ASP.NET context:
IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated)
{
return false;
}
If the user fails authentication, an HttpUnauthorizedResult ActionResult is returned, which produces an HTTP 401(Unauthorized) status code. If it weren’t for ASP.NET Forms Authentication, an HTTP 401 status code would be sent to the browser, which would show the browser’s default login prompt.