Reputation: 7949
In our MVC solution we have two custom implementations of AuthorizeAttribute
- one is named BasicHttpAuthorizeAttribute
and has been used in production for years, and the other RoleAuthorizeAttribute
, which was recently added.
When creating RoleAuthorizeAttribute
I simply copied BasicHttpAuthorizeAttribute
and modified some of the already-overridden methods.
Both attributes serve the purpose of authenticating the user, and the RoleAuthorizeAttribute
of verifying that the user has the required role.
However, RoleAuthorizeAttribute
never authenticates the user. It is simply not being called and instead our MVC controllers throw an exception when a non-logged-in user reaches the controller action and the code requests the context user.
Below is the outline for this custom AuthorizeAttribute
. If I put breakpoints on all of those methods I find that none of them are hit when a request is made.
Can anyone explain why this class is not being used to authenticate users? Why is it that an unauthenticated user is not being redirected to the login page, but if I swap RoleAuthorize
for BasicHttpAuthorize
or simply the base Authorize
then they are redirected?
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class RoleAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
/// <summary>
/// Gets or sets the <see cref="Role"/> enumerations required for authorization.
/// </summary>
public Role[] RequiredRoles
{
get {...}
set {...}
}
public bool RequireSsl { get; set; };
public bool RequireAuthentication { get; set; }
public RoleAuthorizeAttribute(params Role[] requiredRoles)
{
// ...
}
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
// ...
}
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
// ...
}
private bool Authenticate(System.Web.Http.Controllers.HttpActionContext actionContext)
{
// ...
}
public static bool TryGetPrincipal(string authHeader, out IPrincipal principal)
{
// ...
}
public static bool TryGetAuthCookie(out IPrincipal principal)
{
// ...
}
private static string[] ParseAuthHeader(string authHeader)
{
// ...
}
private static bool TryGetPrincipal(string username, string password, out IPrincipal principal)
{
// ...
}
}
And here is an example of its usage:
namespace MyProject.Areas.Customer.Controllers
{
[RoleAuthorize(Role.Customer, Role.CompanyAdmin)]
public partial class OrderController : MyCustomController
{
private static readonly ILog Log = LogManager.GetLogger(typeof (OrderController));
public ActionResult Index(int id)
{
// ...
}
}
}
We use Basic Authentication so there's a header set thus:
I've seen older questions asking about the same problem, but in those cases, they also override an AuthorizeCore
method which no longer seems to be present on the AuthorizeAttribute
class.
Upvotes: 3
Views: 683
Reputation: 7949
I figured out myself why this was happening.
There are two AuthorizeAttributes
- one in the System.Web.Http
namespace and the other in System.Web.Mvc
. I wasn't aware of this and was trying to build a one-size-fits-all attribute, so my attribute was working for WebAPI requests but not for MVC controller requests.
The difference in these two attributes is in the OnAuthorize
method where they each take a different context argument.
Once I had built two separate attributes (which are almost identical), each deriving from a different AuthorizeAttribute
, everything worked as expected.
Upvotes: 5