Reputation: 1594
I am trying to allow anonymous access to the root of my site. If I make a request to site.com/home it allows anonymous access. However, if I request site.com/ I am presented with a login page. So far I have done the following:
In the web.config I authorized "Home" for all users:
<location path="Home">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
In FilterConfig.cs I added the following AuthorizeAttribute:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new System.Web.Mvc.AuthorizeAttribute());
}
My Home Index controller action looks like this:
[AllowAnonymous]
public ActionResult Index()
{
return View();
}
My routes looks like this:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Zoom",
url: "zoom/{id}",
defaults: new { controller = "Zoom", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Is this accomplished with a route? Am I completely missing something?
Upvotes: 2
Views: 2446
Reputation: 1027
First of all, you should NOT use the Webforms way of authorization with the web.config. Get rid of that first. Second, by adding the Authorize attribute as global filter, you're basically applying the Authorize attribute to all controllers and actions, is that really what you want? It is more common to decorate actions methods, or the complete controller. If the controller has the authorize attribute, you can still allow anonymous access for action methods by adding the AllowAnonymous attribute, just like you already did.
Using this approach should just work fine, the routes look good.
Upvotes: 1
Reputation: 55459
You have to implement the logic in the Attribute code to filter it. In other words, you have to check and see if the method/class is annotated with the attribute and then skip authorization if it is (or handle accordingly for your scenario).
Here's an example:
/// <summary>
/// This class is used to ensure that a user has been authenticated before allowing a given method
/// to be called.
/// </summary>
/// <remarks>
/// This class extends the <see cref="AuthorizeAttribute"/> class.
/// </remarks>
public sealed class LoginAuthorize : AuthorizeAttribute
{
/// <summary>
/// The logger used for logging.
/// </summary>
private static readonly ILog Logger = LogManager.GetLogger(typeof(LoginAuthorize));
/// <summary>
/// Handles the authentication check to ensure user has been authenticated before allowing a method
/// to be called.
/// </summary>
/// <param name="filterContext">The authorization context object.</param>
public override void OnAuthorization(AuthorizationContext filterContext)
{
DateTime methodEntryTime = DateTime.Now;
Helper.LogMethodEntry(Logger, MethodBase.GetCurrentMethod(), filterContext);
try
{
// determine if the called method has the AllowAnonymousAttribute, which means we can skip
// authorization
bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)
|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
if (!skipAuthorization)
{
base.OnAuthorization(filterContext);
// make sure required session data is still present
if (string.IsNullOrWhiteSpace(filterContext.HttpContext.Session[Helper.ROLE_NAME] as string))
{
HandleUnauthorizedRequest(filterContext);
}
}
Helper.LogMethodExit(Logger, MethodBase.GetCurrentMethod(), methodEntryTime);
}
catch (Exception e)
{
Helper.LogException(Logger, MethodBase.GetCurrentMethod(), e);
throw;
}
}
/// <summary>
/// Handles unauthorized requests. Redirects user to login page.
/// </summary>
/// <param name="filterContext">The authorization context object.</param>
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
DateTime methodEntryTime = DateTime.Now;
Helper.LogMethodEntry(Logger, MethodBase.GetCurrentMethod(), filterContext);
try
{
base.HandleUnauthorizedRequest(filterContext);
// redirect user to login page
filterContext.Result = new RedirectResult("~/Login");
Helper.LogMethodExit(Logger, MethodBase.GetCurrentMethod(), methodEntryTime);
}
catch (Exception e)
{
Helper.LogException(Logger, MethodBase.GetCurrentMethod(), e);
throw;
}
}
}
}
Then, in Global.asax
you would add this LoginAuthorize
class, like this:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new LoginAuthorize());
filters.Add(new HandleErrorAttribute());
}
Upvotes: 2