Skip to content

Instantly share code, notes, and snippets.

@arthernan
Created April 2, 2013 15:15
Show Gist options
  • Save arthernan/5293014 to your computer and use it in GitHub Desktop.
Save arthernan/5293014 to your computer and use it in GitHub Desktop.
Improved AuthorizeAttribute for MicroSoft MVC4 WebAPI
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Principal;
using System.Threading;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
namespace Infrastructure
{
public class NewAuthorize : AuthorizeAttribute
{
private static readonly string[] _emptyArray = new string[0];
private readonly object _typeId = new object();
private string _roles;
private string[] _rolesSplit = _emptyArray;
private string _users;
private string[] _usersSplit = _emptyArray;
new public string Roles
{
get { return _roles ?? String.Empty; }
set
{
_roles = value;
_rolesSplit = SplitString(value);
}
}
new public string Users
{
get { return _users ?? String.Empty; }
set
{
_users = value;
_usersSplit = SplitString(value);
}
}
protected override bool IsAuthorized(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException("actionContext");
}
IPrincipal user = Thread.CurrentPrincipal;
if (user == null || !user.Identity.IsAuthenticated)
{
return false;
}
return true;
}
protected bool IsAllowed(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException("actionContext");
}
IPrincipal user = Thread.CurrentPrincipal;
if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
{
return false;
}
if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
{
return false;
}
return true;
}
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException("actionContext");
}
if (SkipAuthorization(actionContext))
{
return;
}
if (!IsAuthorized(actionContext))
{
HandleUnauthorizedRequest(actionContext);
}
if (!IsAllowed(actionContext))
{
HandleForbiddenRequest(actionContext);
}
}
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException("actionContext");
}
HttpResponseMessage result = new HttpResponseMessage()
{
StatusCode = HttpStatusCode.Unauthorized,
RequestMessage = actionContext.Request
};
actionContext.Response = result;
}
protected void HandleForbiddenRequest(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException("actionContext");
}
HttpResponseMessage result = new HttpResponseMessage()
{
StatusCode = HttpStatusCode.Forbidden,
RequestMessage = actionContext.Request
};
actionContext.Response = result;
}
private static bool SkipAuthorization(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException("actionContext");
}
return actionContext.ActionDescriptor.GetCustomAttributes().Any()
|| actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes().Any();
}
internal static string[] SplitString(string original)
{
if (String.IsNullOrEmpty(original))
{
return _emptyArray;
}
var split = from piece in original.Split(',')
let trimmed = piece.Trim()
where !String.IsNullOrEmpty(trimmed)
select trimmed;
return split.ToArray();
}
}
}
@twistedstream
Copy link

Nice work on this! A comment and a question:

  • The AuthorizationFilterAttribute method has a compile error with the calls to GetCustomAttributes() unless you pass a type parameter (like the original AuthorizeAttribute does: .GetCustomAttributes<AllowAnonymousAttribute>())
  • Is there any value in inheriting from AuthorizeAttribute? Seems like you've overridden pretty much all functionality in that class ? If so, that pretty much makes a .NET Framework override fail.

@jasonterando
Copy link

Very helpful! Amazed this behavior wasn't in Microsoft's implementation. Only thing I had to tweak to get this to work from a WebAPI controller was:

    IPrincipal user = Thread.CurrentPrincipal;

to

    IPrincipal user = HttpContext.Current.User;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment