I am using default Web Application template for MVC4 in Visual Studio. How can I write Authorize Attribute to redirect user after succesfull login? This attribute should look like this: [UserRedirect("username")] whether anyone use "username" login redirect should be made. Where do I apply this attribute? To the login page or index? Thanks for answer.
You need to override OnAuthorization method of AuthorizeAtribute
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class UserRedirectAttribute: AuthorizeAttribute
{
public string UserName{ get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.onAuthorization(filterContext);
if(base.AuthorizeCore(filterContext.HttpContext) == true)
{
//here put all the a logic for redirect condition ()
if(filterContext.HttpContext.User.Identity.Name.Equals(this.UserName,StringComparer.Ordinal)
{
//if you should do the redirect
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
{
controller = "Redirect controller name",
action = "Redirect action name"
})
);
}
}
}
}
Regarding the usage:
If it is an authorize attribute that is going to replace default authorize attribute you should on any authorized Action/Controller
EDIT:
Based on your last comment you don't have to use an attribute at all. Just add the redirect logic at the end of your login action:
[HttpPost]
public ActionResult Login(LoginModel model)
{
bool userAuthenticationResult = // here goes your authentication logic
if(userAuthenticationResult && HttpContext.User.Identity.Name.Equals(this.UserName,StringComparer.Ordinal))
{
//setup cookie/token any other things you need for the authentication to work
return RedirectToAction("ActionName","ControllerName");
}
}
Related
I am currently working on a POST controller. In the past I've handled logic regarding authentication in the controller itself like this:
[HttpPost]
public HttpResponseMessage Post([FromBody] Foo foo)
{
if (foo.bar !== user.bar){
return;
}
I am not the best c# programmer, so have no clue how this should be handled. While researching I stumbled upon Policies. So I already use a [Authenticated] tag above the controller, but based on if the foo.bar in this example is the same as me.bar I am not allowed to make this post. (So the authenticated tag is for authentication but I want to change the Authorization)
Is it possible that I can make a [Policy=("fooPoster")] and can use the body of the post in there to determine whether I am authorized or not to access the post, or can I only access the global state to determine it?
You can try custom authorization. Refer to the code below.
[HttpPost]
[CustomAuthorization(Foo.bar)]
public HttpResponseMessage Post([FromBody] Foo foo)
{
if (foo.bar !== user.bar)
{
return;
}
}
public class CustomAuthorizationAttribute : AuthorizeAttribute
{
private readonly string allowedroles;
public CustomAuthorizationAttribute(string roles)
{
this.allowedroles = roles;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorize = false;
if (Me.bar != allowedroles)
{
authorize = true;
}
return authorize;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
For more details you can go through here :
I took over an MVC 3 Razorview project from a colleague. I created a forgotten password page, however when clicking on the forgotten password link on the Log on page, the website asks the user to log in. I did some googling and implemented the solution for white listing actions using the [AllowAnonymous] attribute. However this did not resolve the issue.
Stepping through the code the forgotten password action is never called. It is pushed straight to the LogOn action on the Account Controller. The _ViewStart.cshtml has the following code which is called even though the forgotten password layout doesn't use it and has a layout set in the code.
#{
Layout = Request.IsAuthenticated ? "~/Views/Shared/_Layout.cshtml" : null;
}
You have to include all the action methods of the controller, that are used in the view, in the white list(using [AllowAnonymous]). I had the same issue with a RecoverPassword page and I realized that my layout invoked a menu method that wasn't in the white list.
You can try this. http://blog.tomasjansson.com/2011/08/securing-your-asp-net-mvc-3-application/
UPDATE
The following code works fine. It implements the OnAuthorization in the base class itself.
public class MyBaseController : Controller
{
protected override void OnAuthorization(AuthorizationContext filterContext)
{
var skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) ||
filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(
typeof(AllowAnonymousAttribute), true);
if (!skipAuthorization)
{
base.OnAuthorization(filterContext);
if (!User.Identity.IsAuthenticated)//Implement your own logic here
{
var url = new UrlHelper(filterContext.RequestContext);
var logonUrl = url.Action("LogOn", "Home", new { reason = "NotAuthorized" });
filterContext.Result = new RedirectResult(logonUrl);
}
}
}
}
public class HomeController : MyBaseController
{
public ActionResult Index()
{
return View();
}
[AllowAnonymous]
public ActionResult PasswordReset()
{
return Content("reset your password");
}
[AllowAnonymous]
public ActionResult LogOn(string reason)
{
return Content("please log in");
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class AllowAnonymousAttribute : Attribute
{
}
In my database, the system user has a list of modules he/she can access.
I would like to be able to add an authorise attribute which checks that this is the case.
E.g. [authorise(UserID, ControllerName)]
Which goes to some code, ensures that the User with UserID specified, has the controller name in his/her list.
At the moment you can simply bypass the fact the tabs aren't visible, by using the URL. (I have code which already checks if the user has specified access and hides/shows tabs)
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
return false;
}
string currentUser = httpContext.User.Identity.Name;
string currentController = httpContext.Request.RequestContext.RouteData.GetRequiredString("controller");
// TODO: go hit your database and see if currentUser can access
// currentController and return true/false from here
...
}
}
then decorate your controllers or actions:
[MyAuthorize]
public class FooController: Controller
{
...
}
This being said I suspect that you might have gone the wrong way in your database design by storing a list of which user has access to access which controller action. Probably you should have used roles for that. Having the database know about controllers just feels wrong.
So:
[Authorize(Roles = "Foo,Bar")]
public class FooController: Controller
{
...
}
Only users that have the Foo or Bar role can access the FooController.
You can create a new attribute.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class CustomAuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
}
bool authorized = // Perform custom logic
If(!authorized)
{
filterContext.Result = new RedirectResult(/* Your access denied url */);
}
}
}
When you create the model, check the permission
DisplayAdminLink = _permissionService.Authorize(StandardPermissionProvider.AccessAdminPanel),
and in the view
#if (Model.DisplayAdminLink)
{
<li>#T("Account.Administration")
</li>
}
When a users login token has expired (ie. they have been logged out) on a page that has AJAX enabled content, if they select a AJAX link on the page it will appear to complete succesfully. However this is not the case. The content that was returned to the page is the Login Redirection. Is there any way to have the AJAX call redirect to the login page if the user is logged out? From what I can see the obvious way would be to add code to the Controller which would pass an error to the AJAX caller so it would handle the users state however because this is forms authentication the authentication happens prior to the controller being called.
Any thoughts on how to handle this? Thanks in advance!
you can customize [Authorize] attribute like this
public class CustomAuthorize : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
//you can change to any controller or html page.
//filterContext.Result = new RedirectResult("/Account/Login");
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
string destinationUrl = UrlHelper.GenerateContentUrl(FormsAuthentication.LoginUrl, filterContext.HttpContext);
filterContext.Result = new JavaScriptResult()
{
Script = "window.location = '" + destinationUrl + "';"
};
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}
you can use this attribute same like you use [Authorize] attribute on controller or perticular action.
[CustomAuthorize]
public class UserController : Controller
{
// your actions here
}
or
public class UserController : Controller
{
[CustomAuthorize]
Public ActionResult Indes()
{
// your code here
}
}
I have a scenario that I haven't been able to solve:
I'm toying around with creating my own custom authorization attribute for mvc. The main bit of functionality I would like to add is to have the ability to change where the user gets redirected if they are not in a certain role. I don't mind that the system sends them back to the login page if they're not authenticated, but I would like to choose where to send them if they are authenticated but not allowed to access that action method.
Here's is what I would like to do:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public string Action;
public string Controller;
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
// if User is authenticated but not in the correct role
string url = Url.Action(this.Action, this.Controller);
httpContext.Response.Redirect(url);
}
}
And as an added bonus I would like to have access to ViewContext and TempData before I do the redirect.
Any thoughts on how I could get instantiate a UrlHelper and ViewContext in the attribute?
You could override the OnAuthorization method:
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
// Call the AuthorizeCore which should return true or false
if (!this.AuthorizeCore(filterContext.HttpContext))
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary()
{
{ "controller", "home" },
{ "action", "about" },
{ "id", "foo" },
});
}
}
As far as ViewData and TempData are concerned: filterContext.Controller.ViewData and filterContext.Controller.TempData should work inside the OnAuthorization method. And finally if you wish to use an UrlHelper (in this case there's no need because RedirectToRouteResult is better) you could instantiate it:
var urlHelper = new UrlHelper(filterContext.RequestContext);