I have the custom AuthorizeAttribute
where I need to use one of the business layer services to validate some data in the database before giving user a permission to view the resource. In order to be able to allocate this service within the my AuthorizeAttribute
I decided to use service location "anti-pattern", this is the code:
internal class AuthorizeGetGroupByIdAttribute : AuthorizeAttribute
{
private readonly IUserGroupService _userGroupService;
public AuthorizeGetGroupByIdAttribute()
{
_userGroupService = ServiceLocator.Instance.Resolve<IUserGroupService>();
}
//In this method I'm validating whether the user is a member of a group.
//If they are not they won't get a permission to view the resource, which is decorated with this attribute.
protected override bool IsAuthorized(HttpActionContext actionContext)
{
Dictionary<string, string> parameters = actionContext.Request.GetQueryNameValuePairs().ToDictionary(x => x.Key, x => x.Value);
int groupId = int.Parse(parameters["groupId"]);
int currentUserId = HttpContext.Current.User.Identity.GetUserId();
return _userGroupService.IsUserInGroup(currentUserId, groupId);
}
protected override void HandleUnauthorizedRequest(HttpActionContext actionContex)
{
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
base.HandleUnauthorizedRequest(actionContex);
}
else
{
actionContex.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
}
}
}
I have couple of other attributes like this in my application. Using service locator is probably not a good approach. After searching the web a little bit I found some people suggesting to use IAuthorizationFilter
with dependency injection instead. But I don't know how to write this kind of IAuthorizationFilter
. Can you help me writing IAuthorizationFilter
that will do the same thing that the AuthorizeAttribute
above?
So after struggling for a while I think I managed to resolve this issue. Here are the steps you have to do in order to that:
1) First you have to make
GetGroupByIdAttribute
passive, and by passive I mean an empty attribute without any logic within it (it will be used strictly for decoration purposes)2) Then you have to mark a controller method, for which you want to add authorization, with this attribute.
3) In order to write your own
IAuthorizationFilter
you have to implement its methodExecuteAuthorizationFilterAsync
. Here is the full class (I included comments to guide you through the code):4) The last step is to register your filter in the
WebApiConfig
.Now, if needed, I can create additional
IActionFilters
that useIUserGroupService
and then inject this service at the start of the application, fromWebApiConfig
class, into all filters.