1

사용자에게 리소스를 볼 수있는 권한을 부여하기 전에 비즈니스 계층 서비스 중 하나를 사용하여 데이터베이스의 일부 데이터를 확인해야하는 사용자 지정 AuthorizeAttribute이 있습니다. 내 응용 프로그램에서이 같은 다른 속성의 몇 가지있다Asp Net Web Api에서 서비스 위치가있는 AuthorizeAttribute 대신 IAuthorizationFilter를 종속성 주입과 함께 사용하도록 코드를 다시 작성하는 방법?

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

: 위해 내가 서비스 위치 "안티 패턴"을 사용하기로 결정 내 AuthorizeAttribute 내에서이 서비스를 할당 할 수 있도록,이 코드입니다. 서비스 위치 지정자를 사용하는 것은 좋은 방법이 아닙니다. 웹을 조금 검색 한 후에 어떤 사람들은 의존성 삽입으로 IAuthorizationFilter을 사용하도록 제안하는 것을 발견했습니다. 그러나 이런 종류의 글을 쓰는 방법을 모르겠습니다. IAuthorizationFilter. 위의 AuthorizeAttribute과 똑같은 일을 할 IAuthorizationFilter을 작성할 수 있습니까?

답변

2

잠시 고생하고 나서이 문제를 해결할 수있었습니다.

1) 처음에는 GetGroupByIdAttribute을 패시브로 만들어야하고 패시브로는 논리가없는 빈 속성을 의미합니다 (장식 목적으로 엄격하게 사용됩니다)

public class GetGroupByIdAttribute : Attribute 
{ 
} 

2) 그런 다음 권한을 추가하려는 컨트롤러 메소드를이 속성과 함께 표시해야합니다. 직접 작성하기 위해

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

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

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

지금, 나는 IUserGroupService을 사용하여 추가 IActionFilters을 만든 다음 모든 필터로, WebApiConfig 클래스에서, 응용 프로그램의 시작이 서비스를 주입.

+0

필터에서 GetGroupByIdAttribute 대신 AddUserToGroupAttribute를 사용하셨습니까? 또한 이것이 DB에 도달하면 컨텍스트를 처리하는 코드는 어떻게됩니까? – DDiVita

+0

@DDiVita, 수동 속성'GetGroupByIdAttribute'의 이름을 지정하기 위해 이미 답변을 업데이트했습니다. 이 예제에서'_userGroupService'는 비즈니스 레이어의 클래스로 데이터 액세스 레이어를 호출하므로'GetGroupByIdAuthorizationFilter'에 컨텍스트를 처리 할 필요가 없습니다. –