2012-11-08 2 views
1

우리는 다음과 같은 기관과 시스템을 보자ASP.MVC 최선의 보안 방법

    의사는 자신의 요리법을 편집 할 수 있어야한다
  • 의사는 그의 부서 내 의사 만의 조리법을 볼 수 있어야합니다.
  • 의사는 사용 가능한 조리법으로 검색 할 수 있어야합니다.
  • 의사를 사용할 조리법으로 보고서를 생성 할 수 있어야한다는 지금 구현 한 다음 보안 검사를 위해

자세한 사항 : 내가 receipe 엔티티가있을 때, 내가 할 수있는 간단한 방법에 대한 완벽한 작동

public void ValidateAccess(Doctor doctor, Recipe aRecipe, EntityAction action) 
{ 
    if (action == EntityAction.Modify && doctor.ID == aRecipe.Doctor.ID) 
     return; 
    if (action == EntityAction.Read && doctor.DepartmentID == aRecipe.Doctor.DepartmentID) 
     return 
    throw new SecurityException(); 
} 

논리 메서드의 시작 부분에서이 메서드를 호출하여 쉽게 액세스의 유효성을 검사합니다.

하지만 문제가 있습니다. 정확한 엔티티가 없지만 일부 통계가있을 때 검색 및보고를 위해이 솔루션이 작동하지 않습니다.

내가 2 CRITERIAS와 함께 몇 가지 질의를해야합니다, 나는 요소 "someGuid"와 조리법에이 이름이 "aName"환자에 대한 보고서를 생성 할 것을 상상하자 :

var res = RecipeRepository.Query(r => aName.Contains(r.Patient.Name)).SelectMany(r => r.Details).Where(d => d.SomeGuid == someGuid).Sum(d => d.SomeValue); 

이 쿼리는 정확하지 않습니다, 숨겨야 할 것을 포함하여 모든 요리법에 대한 통계를 표시합니다. 이 문제를 해결하려면, 우리는 우리의 질의에 우리의 접근 조건을 추가해야합니다

var res = RecipeRepository.Query(r => aName.Contains(r.Patient.Name) && currentDoctor.DepartmentID == r.Doctor.DepartmentID).SelectMany(r => r.Details).Where(d => d.SomeGuid == someGuid).Sum(d => d.SomeValue); 

문제는 내가 시스템의 각 쿼리에이 부분을 추가해야한다는 것입니다 :

currentDoctor.DepartmentID == r.Doctor.DepartmentID 

을 그래서 지금은 쿼리가 그것은 조리법에 대한 계산을합니다.

UPDATE (2012년 11월 12일)

첫번째 예는 매우 간단하며, 그의 StuartLC 게시물 바와 같이 해결할 수있다. 하지만 Google 시스템에는 더 복잡한 보고서가 있습니다. 예를 들어 - 조리법에 someGuid 구성 요소가있는 모든 환자를 표시합니다. 이제 쿼리가 다른 저장소로 시작되므로 RecipeRepository에서 개인 또는 보호 된 메소드를 적용 할 수 없습니다. 우리는 여전히 쿼리에 직접 우리의 필터를 추가해야이 경우

var res = PatientRepository.Query(p => p.Name.Contains(aName) && p.Recipes.Any(r => r.Details.Any(d => d.SomeGuid == someGuid))); 

:

var res = PatientRepository.Query(p => p.Name.Contains(aName) && p.Recipes.Any(r => currentDoctor.DepartmentID == r.Doctor.DepartmentID && r.Details.Any(d => d.SomeGuid == someGuid))); 

최종 업데이트 다음은 샘플 쿼리입니다.

이 솔루션을 더 쉽게 만들고 각 쿼리에 식 붙여 넣기를 방지하기 위해 적용 할 수있는 패턴이나 방법은 무엇입니까? 답변과 조언을 주시면 감사하겠습니다.

+1

그 흑 마법사와 물약, 의사와 처방, 또는 요리사 및 조리법해야하지 ? – Tr1stan

+0

당신은 도메인 이름에 대해 옳을 수 있습니다, 엔티티는 처방전이어야합니다 ... 계정으로 가져 가겠지만 질문은 액세스 제한에 관한 것입니다. –

+0

물론, 나는 도움이 안되는 중이었고, 때로는 긴 하루가 지나자 ... – Tr1stan

답변

1

Query() 방법은 반환 저장소 패턴 경우 비 구체화 예를 들어, 당신은 도우미 메서드로 데이터 액세스 제한의 우려, 각 'restrictable'엔티티를 리팩토링 할 수 IQueryable<T> :

private IQueryable<Recipe> ApplyAccessFilters(IQueryable<Recipe> query, User user) 
{ 
    IQueryable<Recipe> filteredQuery = query; 

    // Custom method to determine if user is restricted to just his/her recipes 
    if (!CheckUserPermission(currentUser, Access.MaySeeAllRecipies))) 
    { 
     filteredQuery = filteredQuery 
           .Where(r => r.DepartmentId = currentUser.DepartmentId) 
    } // Else no restriction, e.g. Admin Users can access all recipes 

    // Other access related filters here 

    return filteredQuery; 
} 

각을 같은 다음 결과 필터 식을 구축하기 위해이 방법을 사용할 수 있습니다 액세스 제한을 필요로하는 당신의 MVC 컨트롤러 액션의 : 당신은 같은 페이지 매김 같은 다른 문제를 처리 할 수 ​​

var recipes = RecipeRepository.Query(r => r.SomeFields == someFilters); // NB, do NOT materialize the lambda 
var recipesForDoctor = ApplyAccessFilters(recipes, currentUser) // Access Filter 
... 
return View(recipesForDoctor); // [AsEnumerable()] - Consider materializing here 

, 같은 방법으로.

그리고 더 나은, 당신은 필터가 눈에 쉽게이 경우이 액세스 필터 fluent을 만들 수 있습니다

return View(RecipeRepository 
      .Query(r => r.SomeFields == someFilters) 
      .ApplyAccessFilters(currentUser) 
      .Paginate(pagingInfo) 
      .AsEnumerable()); 
+0

해답을 가져 주셔서 감사합니다. RecipeRepository에서 시작하는 모든 쿼리에서 작동하지만 항상 그렇지는 않습니다. 다른 리포지토리에서 쿼리를 시작한 경우에도 적용 할 수있는 좀 더 일반적인 솔루션이 필요하며 레서피는 쿼리 내부에 있습니다 ... 내 질문에 더 나은 일러스트를 생각해 볼 것입니다. –

+0

내 질문에 예제를 하나 더 추가했습니다.이 부분을 살펴보고 그것에 대해 어떻게 생각하는지 말해주십시오. –