Убедитесь, что пользователь X не запрашивает данные пользователя Y

#c# #entity-framework #asp.net-identity

#c# #entity-framework #asp.net-identity

Вопрос:

Допустим, у меня есть объект, у Organisation которого много Student . Для каждого существует логин Organisation , который показывает список связанных Student .

При просмотре списка Student я могу редактировать их, нажав на один из них. Это приводит меня, скажем, к странице /students/edit/<id> .

Запрос для просмотра этой страницы может получить учащихся с моего уровня обслуживания:

 public class StudentService : IStudentService {

     private readonly IRepository _repository; // injected in constructor

     public Student GetStudent(int id) {
          return _repository.Get<Student>(x => x.Id = id);
     }
}
  

Мои вопросы:

  1. Как мне гарантировать, что организация X не запрашивает данные организации Y (например, используя другой идентификатор в строке запроса, который не принадлежит этой зарегистрированной организации)?

  2. Должен ли уровень обслуживания добавлять дополнительные соединения ( amp;amp; x.OrganisationId == <organisation id> ), чтобы убедиться, что текущий вошедший в Organisation систему является единственным, у которого запрашиваются данные? Как мне получить текущего пользователя с уровня обслуживания?

  3. Должен ли я добавить дополнительный параметр в GetStudent(int id, int organisationId) и позволить контроллеру установить его? Похоже, это просто раздувает мои сервисы.

Надеюсь, я хорошо объяснил это, пожалуйста, дайте мне знать, если я сбиваю себя с толку 😉

Ответ №1:

Я бы рекомендовал, чтобы ваша служба знала о текущем аутентифицированном пользователе. Это позволит вам включать Where в каждый запрос ограничивающее предложение, аналогичное приведенному ниже, чтобы пользователи не могли видеть студентов других организаций

  private Student GetStudent(int id) {
      return _repository
        .Get<Student>(x => x.Id = id)
        .Where(s => s.OrganisationId == _currentUser.OrganisationId)
        .FirstOrDefault();
 }
  

Комментарии:

1. Как я могу сделать так, чтобы моя служба знала о текущем вошедшем в систему пользователе? Как мне получить ASP.NET Идентификационный номер пользователя здесь? 🙂

2. Я не хочу создавать зависимость от пользовательского интерфейса от уровня обслуживания.

3. Предполагая, что у вас есть какая-то форма идентификатора пользователя для вашего Identity объекта, которая отображается в поле DB, тогда вы можете предоставить идентификатор текущего пользователя через свою инфраструктуру IoC. В качестве альтернативы вы можете создать пользовательский объект идентификации и предоставить его, что требует больше работы, но более полезно в будущем.

4. возможно ли, чтобы вы привели простой пример того, как предоставить объект идентификации в моей службе?

5. Используете ли вы контейнер DI / IoC?

Ответ №2:

В прошлом году я разработал веб-приложение, в котором был аналогичный сценарий. Что я сделал, так это создал метод с именем GetFilteredQueryable в каждом из моих репозиториев, который принимает в качестве параметра имя пользователя текущего пользователя, вошедшего в систему (мы предпочитаем использовать адрес электронной почты, но на самом деле все работает). Например, при поиске записей учащихся я бы сделал следующее:

 IEnumerable<Student> GetStudentsHavingSubject(string subjectCode, string curUser)
{
    var Students = this.GetFilteredQueryable<Student>(CurUser);
    Students = Students.Where(x => x.subjects.Any(y=>y.SubjectCode == subjectCode));
    return Students.AsEnumerable();
}

IQueryable<Student> GetFilteredQueryable(curUser)
{
    //you could do any other checks in here too, like user level, permissions, etc.
    return DB.Students.Where(x => x.Organization.Users.Any(y=>y.UserName == curUser));
}
  

Ответ №3:

Я бы рекомендовал просто добавить параметр для идентификатора организации. При написании методов всегда представляйте себе написание тестов для вашего метода. Если вам будет неудобно писать тест, вам, вероятно, следует реорганизовать свой метод.

Передача параметра organizationId очень проста и понятна.