Myk*_*ych 2 asp.net authorize-attribute asp.net-web-api iauthorizationfilter asp.net-web-api-filters
我有一个习惯AuthorizeAttribute,在授予用户查看资源的权限之前,需要使用其中一个业务层服务来验证数据库中的某些数据。为了能够在我内部分配此服务,我AuthorizeAttribute决定使用服务位置“反模式”,这是代码:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在我的应用程序中,我还有其他几个类似的属性。使用服务定位器可能不是一个好方法。在网上搜索了一点之后,我发现有些人建议改为使用IAuthorizationFilter依赖项注入。但是我不知道该如何写IAuthorizationFilter。您能帮我写出IAuthorizationFilter与AuthorizeAttribute上述内容相同的内容吗?
因此,经过一段时间的努力,我认为我设法解决了这个问题。为此,您必须执行以下步骤:
1)首先,您必须设置GetGroupByIdAttribute被动属性,被动是指一个空属性,其中没有任何逻辑(它将严格用于装饰目的)
public class GetGroupByIdAttribute : Attribute
{
}
Run Code Online (Sandbox Code Playgroud)
2)然后,您必须使用此属性标记要为其添加授权的控制器方法。
[HttpPost]
[GetGroupById]
public IHttpActionResult GetGroupById(int groupId)
{
//Some code
}
Run Code Online (Sandbox Code Playgroud)
3)为了自己编写IAuthorizationFilter,必须实现其方法ExecuteAuthorizationFilterAsync。这是完整的课程(我提供了一些注释来指导您完成代码):
public class GetGroupByIdAuthorizationFilter : IAuthorizationFilter
{
public bool AllowMultiple { get; set; }
private readonly IUserGroupService _userGroupService;
//As you can see I'm using a constructor injection here
public GetGroupByIdAuthorizationFilter(IUserGroupService userGroupService)
{
_userGroupService = userGroupService;
}
public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
//First I check whether the method is marked with the attribute, if it is then check whether the current user has a permission to use this method
if (actionContext.ActionDescriptor.GetCustomAttributes<GetGroupByIdAttribute>().SingleOrDefault() != null)
{
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();
//If the user is not allowed to view view the resource, then return 403 status code forbidden
if (!_userGroupService.IsUserInGroup(currentUserId, groupId))
{
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.Forbidden));
}
}
//If this line was reached it means the user is allowed to use this method, so just return continuation() which basically means continue processing
return continuation();
}
}
Run Code Online (Sandbox Code Playgroud)
4)最后一步是在中注册过滤器WebApiConfig。
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Here I am registering Dependency Resolver
config.DependencyResolver = ServiceLocator.Instance.DependencyResolver;
//Then I resolve the service I want to use (which should be fine because this is basically the start of the application)
var userGroupService = ServiceLocator.Instance.Resolve<IUserGroupService>();
//And finally I'm registering the IAuthorizationFilter I created
config.Filters.Add(new GetGroupByIdAuthorizationFilter(userGroupService));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Run Code Online (Sandbox Code Playgroud)
现在,如果需要,我可以创建其他IActionFilters用途IUserGroupService,然后在应用程序的开头(从WebApiConfig类)向所有过滤器中注入此服务。
| 归档时间: |
|
| 查看次数: |
1507 次 |
| 最近记录: |