1

私は、ビジネス層サービスの1つを使用して、データベース内の一部のデータを検証してから、リソースを表示する権限をユーザに与える必要があるというカスタムを持っています(AuthorizeAttribute)。私はサービスの場所「アンチパターン」を使用することを決めた私のAuthorizeAttribute以内にこのサービスを割り当てることができるようにするために、これはコードです:IAuthorizationFilterをAsp Net Web Apiのサービスロケーションと共に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); 
     } 
    } 
} 

私は自分のアプリケーションでは、このような他の属性のカップルを持っています。おそらく、サービスロケータを使用するのは良い方法ではありません。 Webを少し検索した後に、代わりにIAuthorizationFilterを使用するように提案している人がいました。しかし、私はこの種の書く方法を知らない。IAuthorizationFilter。あなたは上記のAuthorizeAttributeと同じことをするIAuthorizationFilterと書いてもらえますか?

答えて

2

しばらくの間苦労した後、私はこの問題を解決することができたと思う。

1)最初にGetGroupByIdAttributeをパッシブにする必要があります。パッシブでは、論理的に空の属性を意味します(装飾目的では厳密に使用されます)

public class GetGroupByIdAttribute : Attribute 
{ 
} 

2)次に、あなたがこの属性で、承認を追加するコントローラメソッドを、マークする必要があります。あなた自身を書き込むためには

[HttpPost] 
[GetGroupById] 
public IHttpActionResult GetGroupById(int groupId) 
{ 
    //Some code 
} 

3)IAuthorizationFilterあなたはその方法ExecuteAuthorizationFilterAsyncを実装する必要があります。最後のステップはWebApiConfigであなたのフィルタを登録することである

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(); 
    } 
} 

4):ここでは完全なクラスは、(私はコードをご案内するコメントを含む)です。今

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 } 
     );    
    } 
} 

、必要であれば、私はIUserGroupServiceを使用して、アプリケーションの開始時に、WebApiConfigクラスから、すべてのフィルタには、このサービスを注入追加IActionFiltersを作成することができます。

+0

フィルタでGetGroupByIdAttributeの代わりにAddUserToGroupAttributeを使用しましたか?また、これがDBにヒットした場合、どのようにコードがコンテキストを破棄していますか? – DDiVita

+0

@DDiVita、パッシブアトリビュートの名前を「GetGroupByIdAttribute」としました。私はすでに自分の答えを更新しました。この例では、 '_userGroupService'はビジネス層からのクラスであり、そこにデータアクセス層を呼び出します。したがって、' GetGroupByIdAuthorizationFilter 'にコンテキストを配置する必要はありません。 –

関連する問題