MVC Controller with User Access Only by Session - c#

I am currently building a user login system in MVC 5 for practice. What I wanna do is, making a controller only accessable if you have the session "UserId".
Surely, I could just make an if statement in every action, like this:
public ActionResult Index()
{
if (Session["UserId"] != null)
{
return View();
}
else
{
return RedirectToRoute("Home");
}
}
But is there a way I can make that happen with all the actions in the controller?
Bonus info:
I have 2 controllers
- HomeController
- AccountController

You would implement an authorize filter and apply that filter to your controller.
Something like this:
public class CustomAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
if (filterContext.HttpContext.Session["UserId"] == null)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
Then you could apply the [CustomAuthentication] attribute to your controller directly, or you can do it by each action in your controller. Something like this:
[CustomAuthentication]//<-- If you put it here, it applies to the whole controller
public class HomeController : Controller
{
[CustomAuthentication]//<-- Here it only applies to the Index action
public ActionResult Index()
{
return View();
}
}

I believe what you are looking for is a custom ActionFilter. Code in an ActionFilter can be executed before the ActionResult, allowing you to redirect anyone without the UserId session.
Instead of putting code in every ActionResult you would do something like this
[MyCustomActionFilter]
public ActionResult Index()
{
return View();
}
Here is a tutorial on how to create one Custom Action filters in MVC

Related

The controller for path ... was not found or does not implement IController

I am writing an application using ASP.NET MVC 5 using c#. I have a need to add a global menu on the upper right hand side of the application. I was advised other SO to use action with ChildActionOnly attribute.
So here is what I have done.
I created a BaseController like this
public class BaseController : Controller
{
[ChildActionOnly]
public ActionResult ClientsMenu()
{
using (SomeContext db = new SomeContext())
{
return PartialView(db.Database.SqlQuery<Client>("SELECT * FROM clients").ToList());
}
}
}
Then I inherited all my controllers from BaseController like so
public class TasksController : BaseController
{
public ActionResult Index(int ClientId)
{
...
return View();
}
public ActionResult Show(int SurveyId)
{
...
return View();
}
}
To render the ClientsMenu in my layout I added the following code
#Html.Action("ClientsMenu", "Menus")
Now when I run my application I get the following error
The controller for path '/Tasks/Index' was not found or does not implement IController.
When I remove #Html.Action("ClientsMenu", "Menus") from the layout everything works fine but the global menu does not show of course.
What can I do to resolve this issue?
Updated
Here is what I have done after the feedback I got from the comments below
public class TasksController : Controller
{
[ChildActionOnly]
public ActionResult ClientsMenu()
{
using (SomeContext db = new SomeContext())
{
return PartialView(db.Database.SqlQuery<Client>("SELECT * FROM clients").ToList());
}
}
public ActionResult Index(int ClientId)
{
...
return View();
}
public ActionResult Show(int SurveyId)
{
...
return View();
}
}
but still the same error
Take ClientMenus Action out of the BaseController and put it into its own controller MenusController. You can then call that controller from your Views.
#Html.Action("ClientsMenu", "Menus")
In your example you don't have a MenusContoller which is what #Html.Action("ClientsMenu", "Menus") is looking for.
The Phil Haacked - Html.RenderAction and Html.Action article linked to by the other post provided a good example for you to follow.

C# mvc5 - Easy way to check if user is authenticated in each controller method

I have a controller that I only want authenticated users to be able to access. Do I have to put a check in each method in my controller to verify a user is authenticated, or is there another way to handle this? Can I use annotations to do this instead?
Example from my controller:
public ActionResult Index()
{
if (UserVerified())
{
...
}
return RedirectToAction("Login", "Account");
}
public ActionResult FacebookLogin()
{
if (UserVerified())
{
....
}
return RedirectToAction("Login", "Account");
}
private bool UserVerified()
{
if (User != null && User.Identity != null && User.Identity.IsAuthenticated)
{
return true;
}
return false;
}
You can use AuthorizeAttribute for it.
Put it to every action.
[Authorize]
public ActionResult Index()
{
}
[Authorize]
public ActionResult FacebookLogin()
{
}
It will do the whole work for you. It checks whether the currect user is authenticated. If he is authenticated - proceeds to the action, if he is not - returns to the home page.
You can also add this attribute to a controller. Then all actions will require authorization.
[Authorize]
public class HomeController
{
public ActionResult Index()
{
}
public ActionResult FacebookLogin()
{
}
}
Update: And, yes, as Kamil said. Read this article, please.
http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api
You spend some time now and will spend much less time having questions about ASP.NET authentication in future.
By the way, you don't need to check for
User != null && User.Identity != null
If you are using default authentication then you can be always sure that User.Identity is a proper object. You can access User.Identity.IsAuthenticated directly.
Using Authorize attribute is way to go (already answered here). In addition, if you may want to implement some other business rules or filtering checks, you can create a filter class inheriting from AuthorizeAttribute.
e.g.
public class CustomAuthorizeFilter: AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
return false; //User not Authorized
}
else
{
//Check your conditions here
}
}
}
Then decorate your controller or Action as:
[CustomAuthorizeFilter]
public class SomeController
{
}
You can either user [Authorize] attribute which is inbuilt. Or you can develop your custom attribute for the same purpose.
You can start from here for your own attribute:
Create custom attribute
If you want to perform validation on each action method, then put that attribute on Controller level rather than each action method.
You can use [Authorize] attribute above controller methods.
Please follow this link
If you want the authentication rules to apply to all controller actions you can do this:
[someAuthAttribute]
public class HomeController : Controller
{
// pseudo
public ActionResult Index() {
return response;
}
public ActionResult FacebookLogin(){
return response;
}
}
Where Index() and FacebookLogin() will adhere to the authentication rules of [someAuthAttribute]. You can also use this "hierarchy" to apply more specific rules to your action methods. Like this:
[someAuthAttribute]
public class HomeController : Controller
{
// pseudo
public ActionResult Index() {
return response;
}
[someFBAuthAttribute]
public ActionResult FacebookLogin(){
return response;
}
}
You can inherit authorization from a base controller.
[Authorize(Roles = #"Domain\Group")]
public class BaseController : Controller
public class ChildController : BaseController

Sessions in Asp.NET MVC 4

Can anybody please tell me how to handle sessions in asp.net MVC 4. I am aware about this Session variable and I know how to use it.
Session["login"] = true; //We can use it in controller to check the whether user logged in or not.
Above code snippet is enough to handle sessions on small web application. But, what if I have many controllers and actions and I am working on a large application, In this case I cant use session variable in each action.
Is there is any generic place where I can check my session variables or any other solution ?
1st Way:
I used to write a Base Controller class and all other Controllers inherit from it that need to authenticated before access:
public class DefaultController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Session["User"] == null)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 403;
filterContext.Result = new JsonResult { Data = "LogOut", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
else
filterContext.Result = RedirectToAction("Login", "Account");
}
else
{
//base.Execute(filterContext.RequestContext);
}
}
}
and inherit from Base Controller in the ones for which user must be logged in:
public class LeaveController : DefaultController
{
}
Another way is to write your own authorizaion attribute.
See Filter and Attributes in asp.net mvc
2nd Way:
Here is sample for custom filter attribute, create class which inherits from ActionFilterAttribute:
public class SessionTimeoutAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Session["someValueYouLookFor"] == null)
{
filterContext.Result = new RedirectResult("~/Home/Index"); // redirect to login action
}
else
{
// continue normal execution
}
}
}
and put it on Controller or Action:
[SessionTimeout]
public ActionResult Index()
{
}
Definitely, you can use Authentication filter if you're using MVC 5.
for simplest way, you can have a baseController, and all other controller should inherit that controller, and in baseController you can override that OnActionExecuting event, to verify if session is there or not.
for ex.
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (Convert.ToBoolean(Session["login"]))
{
//Authenticated
}
else
{
//Kick to login page
}
}
All other controller should inherit this baseController
public class HomeController : BaseController
{
public ActionResult Index()
{
return View();
}
public ActionResult Test()
{
return View();
}
}
This way, before your action method start executing, it will be verified through baseController's OnActionExecuting event.

ASP.NET MVC change default route on login/logout

I have a pretty simple requirement.
If the user goes to http://www.somedomain.com/ and is not logged, I want MVC to route user to HomeController.
If the user goes to http://www.somedomain.com/ and is logged in, I want MVC to route user to ClientController.
Is there an easy solution for this problem?
Thank You very much!
In your HomeController, Index action, redirect to the ClientController if the HttpContext.User is not null:
public class HomeController : Controller
{
public ActionResult Index()
{
if (HttpContext.User != null)
{
RedirectToAction("Index", "Client");
}
}
}
EDIT: Or Use Request.IsAuthenticated
public class HomeController : Controller
{
public ActionResult Index()
{
if (Request.IsAuthenticated)
{
RedirectToAction("Index", "Client");
}
}
}
There are quite a few ways to solve this.
Depending on your requirements you could implement an IAuthorizationFilter for this purpose and implement the OnAuthorization method something like this.
public void OnAuthorization(AuthorizationContext filterContext)
{
IUser user = _currentUserProvider.CurrentUser;
if (user != null)
{
// you can perform perform additional user-authorization here...
if(_authorizationService.IsAuthorized(user))
{
//user is authorized
return;
}
else
{
HandleUnAuthorizedRequest(filterContext);
return;
}
}
//user is not authenticated (not logged in)
HandleUnAuthenticatedRequest(filterContext);
}
You then use the actionFilter on your controller method or controller class.
See http://msdn.microsoft.com/en-us/library/dd410209(v=VS.90).aspx for more information about Action Filters.
Now, if you want all unauthenticated requests to go to the ClientController, you can handle the AuthenticateRequest event in your HttpApplication (usually global.asax.cs) class and implement something like in the actionFilter above.

Enforce Action Filter on all Controller Actions (C# / ASP.NET MVC)

I made a new action filter (attribute, similar to [Authorize]) which authorizes access to a controller action based on a session value. However, I'm basically decorating all my controller actions with that attribute (with the exception of very few).
So, I thought it would be better to have that Action Filter always executed except in cases where I attach an [ExemptFromAuthorize] attribute to a controller action? (Maybe via inheriting to my own Controller class?)
How can I do this?
Running with jeef3's answer, I came up with this. It could use more error checking and robustness like multiple delimited actions, but the general idea works.
In your specific case, you could test for the session value and decide to return out of the authorization also.
public class AuthorizeWithExemptionsAttribute : AuthorizeAttribute
{
public string Exemption { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.RouteData.GetRequiredString("action") == Exemption)
return;
base.OnAuthorization(filterContext);
}
}
Usage:
[AuthorizeWithExemptions(Roles="admin", ExemptAction="Index")]
public class AdminController : Controller
...
Check out my article on codeproject -
http://www.codeproject.com/KB/web-security/AuthorizeWithExemptions.aspx
In this article, I'll provide you with a solution for securing ASP.NET MVC application's controllers in a way that all the actions are secured except those you define as unsecure.
snipper from the code:
public override void OnAuthorization(AuthorizationContext filterContext)
{
ActionDescriptor action = filterContext.ActionDescriptor;
bool IsUnsecured = action.GetCustomAttributes(
typeof(UnsecuredActionAttribute), true).Count() > 0;
//If doesn't have UnsecuredActionAttribute - then do the authorization
filterContext.HttpContext.SkipAuthorization = IsUnsecured;
base.OnAuthorization(filterContext);
}
I understand the question is pretty outdated but anyway.. If you wish to apply filter to all actions just add following lines into Global.asax:
protected void Application_Start()
{
// your code here and then
RegisterGlobalFilters(GlobalFilters.Filters);
}
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyActionFilterAttribute());
}
And in action filter you can just check if action has any other attributes in following way:
public void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.ActionDescriptor.IsDefined(typeof(AnotherActionAttribute), false))
{
// do what you want to do
}
}
Maybe try and add an Except property to your first attribute?
[MyAuthenticate(Exempt="View")]
public class MyController : Controller
{
public ActionResult Edit()
{
// Protected
}
public ActionResult View()
{
// Accessible by all
}
}
You can add the attribute to the class to have it apply to all methods in that class
[Authenticate]
public class AccountController : Controller
{
public ActionResult Index()
{
return View();
}
}
I don't know how to exclude a specific method from a class-level attribute. Maybe use a separate controller for unauthenticated requests?
For anyone reading this in 2013+, MVC4 now supports the use of
[AllowAnonymous]
You can put Authorize on the controller, and then Allow Anonymous on
any functions you do not want to authorize.
Example:
[Authorize]
public class HomeController : Controller {
[AllowAnonymous]
public ActionResult Index()
{
}
}
Would this work with a custom [MyAuthorize] filter or does it only work with [Authorize]
For anyone reading this in 2013+, MVC4 now supports the use of [AllowAnonymous]
You can put Authorize on the controller, and then Allow Anonymous on any functions you do not want to authorize.
Example:
[Authorize]
public class HomeController : Controller
{
[AllowAnonymous]
public ActionResult Index()
{
}
}

Categories

Resources