Бөлісу құралы:


Авторизация на основе пользователей (C#)

Скотт Митчелл

Примечание

С момента написания этой статьи поставщики членства ASP.NET были заменены ASP.NET Identity. Мы настоятельно рекомендуем обновить приложения для использования платформы ASP.NET Identity , а не поставщиков членства, которые были представлены на момент написания этой статьи. ASP.NET Identity имеет ряд преимуществ по сравнению с системой членства ASP.NET, включая :

  • более высокая производительность;
  • Улучшенная расширяемость и тестируемость
  • Поддержка OAuth, OpenID Connect и двухфакторной проверки подлинности
  • Поддержка удостоверений на основе утверждений
  • Улучшенное взаимодействие с ASP.Net Core

Скачать код или скачать PDF-файл

В этом руководстве мы рассмотрим ограничение доступа к страницам и ограничение функциональности на уровне страниц с помощью различных методов.

Введение

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

ASP.NET упрощает определение правил авторизации на основе пользователей. С помощью небольшой разметки в Web.configможно заблокировать определенные веб-страницы или целые каталоги, чтобы они были доступны только для указанного подмножества пользователей. Функции на уровне страницы можно включать или отключать в зависимости от текущего пользователя, выполнившего вход, программными и декларативными средствами.

В этом руководстве мы рассмотрим ограничение доступа к страницам и ограничение функциональности на уровне страниц с помощью различных методов. Приступим к работе!

Взгляд на рабочий процесс авторизации URL-адресов

Как описано в руководстве Обзор проверки подлинности с помощью форм , когда среда выполнения ASP.NET обрабатывает запрос на ASP.NET ресурс, запрос вызывает ряд событий в течение своего жизненного цикла. Модули HTTP — это управляемые классы, код которых выполняется в ответ на определенное событие в жизненном цикле запроса. ASP.NET поставляется с рядом модулей HTTP, которые выполняют важные задачи в фоновом режиме.

Одним из таких модулей HTTP является FormsAuthenticationModule. Как обсуждалось в предыдущих руководствах, основной FormsAuthenticationModule функцией является определение идентификатора текущего запроса. Это достигается путем проверки запроса проверки подлинности форм, который находится в файле cookie или внедрен в URL-адрес. Эта идентификация выполняется во время AuthenticateRequest события.

Другим важным модулем UrlAuthorizationModuleHTTP является , который возникает в ответ на AuthorizeRequest событие (которое происходит после AuthenticateRequest события). Проверяет UrlAuthorizationModule разметку конфигурации в , Web.config чтобы определить, имеет ли текущее удостоверение право на посещение указанной страницы. Этот процесс называется авторизацией URL-адреса.

Мы рассмотрим синтаксис правил авторизации URL-адресов на шаге 1, но сначала рассмотрим UrlAuthorizationModule , что делает в зависимости от того, авторизован ли запрос. UrlAuthorizationModule Если определяет, что запрос авторизован, он не выполняет никаких действий, и запрос продолжается в течение своего жизненного цикла. Однако если запрос не авторизован, то UrlAuthorizationModule прерывает жизненный цикл и указывает объекту Response вернуть состояние HTTP 401 Unauthorized . При использовании проверки подлинности с помощью форм это состояние HTTP 401 никогда не возвращается клиенту, так как при FormsAuthenticationModule обнаружении состояния HTTP 401 изменяется на HTTP 302 Перенаправление на страницу входа.

На рисунке 1 показан рабочий процесс конвейера ASP.NET, FormsAuthenticationModuleи при поступлении UrlAuthorizationModule несанкционированного запроса. В частности, на рис. 1 показан запрос анонимного посетителя для ProtectedPage.aspxстраницы, которая запрещает доступ анонимным пользователям. Так как посетитель является анонимным, UrlAuthorizationModule объект прерывает запрос и возвращает состояние HTTP 401 Не авторизовано. FormsAuthenticationModule Затем преобразует состояние 401 в 302 Redirect на страницу входа. После проверки подлинности пользователя на странице входа он перенаправляется по адресу ProtectedPage.aspx. На FormsAuthenticationModule этот раз идентифицирует пользователя на основе его запроса проверки подлинности. Теперь, когда посетитель прошел проверку подлинности UrlAuthorizationModule , он разрешает доступ к странице.

Рабочий процесс проверки подлинности на основе форм и авторизации URL-адресов

Рис. 1. Рабочий процесс проверки подлинности на основе форм и авторизации URL-адресов (щелкните для просмотра полноразмерного изображения)

На рисунке 1 показано взаимодействие, которое происходит, когда анонимный посетитель пытается получить доступ к ресурсу, недоступному анонимным пользователям. В этом случае анонимный посетитель перенаправляется на страницу входа с той страницей, к которым он пытался перейти, указанной в строках запроса. После успешного входа пользователя он автоматически перенаправляется обратно к ресурсу, который он пытался просмотреть.

Когда анонимный пользователь выполняет неавторизованный запрос, этот рабочий процесс прост, и посетителю легко понять, что произошло и почему. Но имейте в виду, что FormsAuthenticationModule перенаправляет любого неавторизованного пользователя на страницу входа, даже если запрос выполнен пользователем, прошедшим проверку подлинности. Это может привести к путанице, если пользователь, прошедший проверку подлинности, попытается посетить страницу, для которой у нее нет полномочий.

Представьте, что на нашем веб-сайте настроены правила авторизации URL-адресов таким образом, что ASP.NET страница OnlyTito.aspx была доступна только для Tito. Теперь представьте, что Сэм посещает сайт, входит в систему, а затем пытается посетить OnlyTito.aspx. приостанавливает UrlAuthorizationModule жизненный цикл запроса и возвращает состояние HTTP 401 Unauthorized, которое FormsAuthenticationModule будет обнаруживать, а затем перенаправлять Сэма на страницу входа. Поскольку Сэм уже вошел в систему, она может задаться вопросом, почему она была отправлена обратно на страницу входа. Она может привести к тому, что ее учетные данные для входа были каким-то образом потеряны или что она ввела недопустимые учетные данные. Если Сэм повторно войдет свои учетные данные со страницы входа, она будет входить в систему (снова) и перенаправляться по адресу OnlyTito.aspx. Компонент UrlAuthorizationModule обнаружит, что Сэм не может посетить эту страницу, и она вернется на страницу входа.

На рисунке 2 показан этот запутанный рабочий процесс.

Рабочий процесс по умолчанию может привести к запутанным циклам

Рис. 2. Рабочий процесс по умолчанию может привести к запутанным циклам (щелкните для просмотра полноразмерного изображения)

Рабочий процесс, показанный на рисунке 2, может быстро понять даже самых подкованных на компьютере посетителей. Мы рассмотрим способы предотвращения этого запутанного цикла на шаге 2.

Примечание

ASP.NET использует два механизма для определения того, может ли текущий пользователь получить доступ к определенной веб-странице: авторизация URL-адреса и авторизация файла. Авторизация файла реализуется службой FileAuthorizationModule, которая определяет полномочия, проконсультировавшись с запрошенными списками управления доступом к файлам. Авторизация файла чаще всего используется с проверкой подлинности Windows, так как списки управления доступом — это разрешения, которые применяются к учетным записям Windows. При использовании проверки подлинности с помощью форм все запросы на уровне операционной системы и файловой системы выполняются одной учетной записью Windows, независимо от того, какой пользователь посещает сайт. Так как в этой серии руководств основное внимание уделяется проверке подлинности с помощью форм, мы не будем обсуждать авторизацию файлов.

Область авторизации URL-адреса

— это управляемый UrlAuthorizationModule код, который является частью среды выполнения ASP.NET. До версии 7 веб-сервера служб IIS существовал отдельный барьер между конвейером HTTP iis и конвейером среды выполнения ASP.NET. Короче говоря, в IIS 6 и более ранних версиях — ASP. UrlAuthorizationModule NET выполняется только при делегировании запроса из IIS в среду выполнения ASP.NET. По умолчанию IIS обрабатывает само статическое содержимое, например HTML-страницы и ФАЙЛЫ CSS, JavaScript и изображения, и передает запросы в среду выполнения ASP.NET только при запросе страницы с расширением .aspx, .asmxили .ashx .

Однако IIS 7 позволяет использовать интегрированные конвейеры IIS и ASP.NET. С помощью нескольких параметров конфигурации можно настроить IIS 7 для вызова UrlAuthorizationModule для всех запросов. Это означает, что правила авторизации URL-адресов можно определить для файлов любого типа. Кроме того, IIS 7 включает собственный механизм авторизации URL-адресов. Дополнительные сведения об интеграции ASP.NET и встроенных функциях авторизации URL-адресов IIS 7 см. в статье Общие сведения об авторизации URL-адресов IIS7. Чтобы более подробно ознакомиться с интеграцией ASP.NET и IIS 7, ознакомьтесь с книгой Шахрама Хосрави Professional IIS 7 and ASP.NET Integrated Programming (ISBN: 978-0470152539).

В двух словах, в версиях, предшествующих IIS 7, правила авторизации URL-адресов применяются только к ресурсам, обрабатываемых средой выполнения ASP.NET. Но в IIS 7 можно использовать встроенную функцию авторизации URL-адресов IIS или интегрировать ASP. NET входит UrlAuthorizationModule в конвейер HTTP СЛУЖБ IIS, тем самым расширяя эту функциональность на все запросы.

Примечание

Существуют некоторые тонкие, но важные различия в том, как ASP. UrlAuthorizationModule Функция авторизации URL-адресов в NET и IIS 7 обрабатывает правила авторизации. В этом руководстве не рассматриваются функции авторизации URL-адресов IIS 7 и различия в анализе правил авторизации по сравнению UrlAuthorizationModuleс . Дополнительные сведения по этим темам см. в документации по IIS 7 на сайте MSDN или в www.iis.net.

Шаг 1. Определение правил авторизации URL-адресов вWeb.config

Определяет UrlAuthorizationModule , следует ли предоставлять или запрещать доступ к запрошенному ресурсу для определенного удостоверения на основе правил авторизации URL-адресов, определенных в конфигурации приложения. Правила авторизации изложены в элементе<authorization> в виде дочерних <allow> элементов и <deny> . Каждый <allow> дочерний элемент и <deny> может указывать следующее:

  • Конкретный пользователь
  • Список пользователей с разделителями-запятыми
  • Все анонимные пользователи, обозначенные вопросительным знаком (?)
  • Все пользователи, обозначенные звездочкой (*)

В следующей разметке показано, как использовать правила авторизации URL-адресов, чтобы разрешить пользователям Tito и Scott и запретить все остальные.

<authorization>
 <allow users="Tito, Scott" />
 <deny users="*" />
</authorization>

Элемент <allow> определяет, какие пользователи разрешены ( Tito и Scott), в то время как <deny> элемент указывает, что все пользователи запрещены.

Примечание

Элементы <allow> и <deny> также могут указывать правила авторизации для ролей. Мы рассмотрим авторизацию на основе ролей в следующем руководстве.

Следующий параметр предоставляет доступ всем пользователям, кроме Сэма (включая анонимных посетителей):

<authorization>
 <deny users="Sam" />
</authorization>

Чтобы разрешить только прошедших проверку подлинности пользователей, используйте следующую конфигурацию, которая запрещает доступ всем анонимным пользователям:

<authorization>
 <deny users="?" />
</authorization>

Правила авторизации определяются в элементе <system.web> в Web.config и применяются ко всем ASP.NET ресурсам в веб-приложении. Часто приложение имеет разные правила авторизации для разных разделов. Например, на сайте электронной коммерции все посетители могут просматривать продукты, просматривать отзывы о продуктах, выполнять поиск в каталоге и т. д. Однако только пользователи, прошедшие проверку подлинности, могут обращаться к оформлению заказа или страницам для управления журналом доставки. Кроме того, могут быть части сайта, доступные только избранным пользователям, например администраторам сайта.

ASP.NET упрощает определение различных правил авторизации для разных файлов и папок на сайте. Правила авторизации, указанные в файле корневой Web.config папки, применяются ко всем ASP.NET ресурсам на сайте. Однако эти параметры авторизации по умолчанию можно переопределить для определенной папки, добавив Web.config с разделом <authorization> .

Давайте обновим наш веб-сайт, чтобы только прошедшие проверку подлинности пользователи могли посещать страницы ASP.NET в папке Membership . Для этого необходимо добавить Web.config файл в папку Membership и настроить параметры авторизации для запрета анонимным пользователям. Щелкните правой Membership кнопкой мыши папку в Обозреватель Решения, выберите в контекстном меню меню Добавить новый элемент и добавьте новый веб-файл конфигурации с именем Web.config.

Добавление файла Web.config в папку членства

Рис. 3. Добавление Web.config файла в папку Membership (щелкните для просмотра полноразмерного изображения)

На этом этапе проект должен содержать два Web.config файла: один в корневом каталоге и один в папке Membership .

Теперь приложение должно содержать два файла Web.config

Рис. 4. Теперь приложение должно содержать два Web.config файла (щелкните для просмотра полноразмерного изображения)

Обновите файл конфигурации в папке Membership , чтобы запретить доступ анонимным пользователям.

<?xml version="1.0"?>
<configuration>
 <system.web>
 <authorization>
 <deny users="?" />
 </authorization>
 </system.web>
</configuration>

Вот и все!

Чтобы проверить это изменение, посетите домашнюю страницу в браузере и убедитесь, что вы вышли из системы. Так как по умолчанию приложение ASP.NET разрешает всем посетителям, а мы не вносим никаких изменений авторизации в файл корневого Web.config каталога, мы можем посетить файлы в корневом каталоге в качестве анонимного посетителя.

Щелкните ссылку Создание учетных записей пользователей в левом столбце. Откроется ~/Membership/CreatingUserAccounts.aspx. Web.config Так как файл в папке Membership определяет правила авторизации для запрета анонимного UrlAuthorizationModule доступа, запрос прерывается и возвращается состояние HTTP 401 Unauthorized. Изменяет FormsAuthenticationModule состояние перенаправления 302, отправляя нас на страницу входа. Обратите внимание, что страница, к которому мы пытались получить доступ (CreatingUserAccounts.aspx), передается на страницу входа с помощью ReturnUrl параметра querystring.

Так как правила авторизации URL-адресов запрещают анонимный доступ, мы перенаправляемся на страницу входа

Рис. 5. Так как правила авторизации URL-адресов запрещают анонимный доступ, мы перенаправляемы на страницу входа (щелкните для просмотра полноразмерного изображения)

После успешного входа мы перенаправляемся на страницу CreatingUserAccounts.aspx . На этот UrlAuthorizationModule раз разрешает доступ к странице, так как мы больше не анонимны.

Применение правил авторизации URL-адресов к определенному расположению

Параметры авторизации, определенные в <system.web> разделе , Web.config применяются ко всем ASP.NET ресурсам в этом каталоге и его подкаталогах (до тех пор, пока не будет переопределен другим Web.config файлом). Однако в некоторых случаях может потребоваться, чтобы все ASP.NET ресурсы в определенном каталоге имели определенную конфигурацию авторизации, за исключением одной или двух определенных страниц. Это можно сделать, добавив <location> элемент в Web.config, указав его на файл, правила авторизации которого отличаются, и определив его уникальные правила авторизации в нем.

Чтобы проиллюстрировать использование <location> элемента для переопределения параметров конфигурации для определенного ресурса, давайте настроим параметры авторизации таким образом, чтобы только Tito смог посетить CreatingUserAccounts.aspx. Для этого добавьте <location> элемент в Membership файл папки Web.config и обновите ее разметку, чтобы она выглядела следующим образом:

<?xml version="1.0"?>
<configuration>
 <system.web>
 <authorization>
 <deny users="?" />
 </authorization>
 </system.web>

 <location path="CreatingUserAccounts.aspx">
 <system.web>
 <authorization>
 <allow users="Tito" />
 <deny users="*" />
 </authorization>
 </system.web>
 </location>
</configuration>

Элемент <authorization> в <system.web> определяет правила авторизации URL-адресов по умолчанию для ASP.NET ресурсов в папке Membership и ее вложенных папках. Элемент <location> позволяет переопределить эти правила для определенного ресурса. В приведенной выше разметке <location> элемент ссылается на страницу CreatingUserAccounts.aspx и задает ее правила авторизации, например разрешать Tito, но запрещать все остальные.

Чтобы проверить это изменение авторизации, начните с посещения веб-сайта в качестве анонимного пользователя. При попытке посетить любую страницу в папке Membership , например UserBasedAuthorization.aspx, UrlAuthorizationModule объект отклонит запрос, и вы будете перенаправлены на страницу входа. После входа в систему как, скажем, Scott, вы можете посетить любую страницу в папке Membership , кромеCreatingUserAccounts.aspx. Попытка войти CreatingUserAccounts.aspx в систему как любой пользователь, кроме Тито, приведет к попытке несанкционированного доступа, перенаправив вас обратно на страницу входа.

Примечание

Элемент <location> должен отображаться за пределами элемента конфигурации <system.web> . Необходимо использовать отдельный <location> элемент для каждого ресурса, параметры авторизации которого требуется переопределить.

Просмотр того, какUrlAuthorizationModuleиспользует правила авторизации для предоставления или запрета доступа

Определяет UrlAuthorizationModule , следует ли авторизовать определенное удостоверение для определенного URL-адреса, анализируя правила авторизации URL-адресов по одному, начиная с первого и отрабатывая путь вниз. Как только совпадение найдено, пользователю предоставляется или запрещается доступ в зависимости от того, было ли найдено совпадение в элементе <allow> или <deny> . Если совпадение не найдено, пользователю предоставляется доступ. Следовательно, если требуется ограничить доступ, необходимо использовать <deny> элемент в качестве последнего элемента в конфигурации авторизации URL-адресов. Если опустить<deny>элемент, всем пользователям будет предоставлен доступ.

Чтобы лучше понять процесс, используемый UrlAuthorizationModule для определения центра, рассмотрим примеры правил авторизации URL-адресов, которые мы рассмотрели ранее на этом шаге. Первое правило — это элемент, разрешающий <allow> доступ к Тито и Скотту. Второе правило — это <deny> элемент, который запрещает доступ всем пользователям. Если анонимный пользователь посещает, UrlAuthorizationModule начинается с вопроса" Является ли анонимным Скотт или Тито? Ответ, очевидно, нет, поэтому он переходит ко второму правилу. Является ли анонимным в наборе всех? Так как ответ на этот вопрос — Да, <deny> правило будет введено в действие, и посетитель перенаправляется на страницу входа. Аналогичным образом, если Jisun посещает, UrlAuthorizationModule начинается с вопроса, Является Ли Джисун либо Скотт или Тито? Поскольку она не, UrlAuthorizationModule переходит ко второму вопросу, Является ли Джисун в наборе всех? Она, так что ей тоже отказано в доступе. Наконец, если Тито посещает, первый вопрос, заданный UrlAuthorizationModule , является положительным ответом, поэтому Тито получает доступ.

UrlAuthorizationModule Так как обрабатывает правила авторизации сверху вниз, останавливаясь на любом совпадении, важно иметь более конкретные правила перед менее конкретными. То есть, чтобы определить правила авторизации, которые запрещают Jisun и анонимных пользователей, но разрешают всех остальных пользователей, прошедших проверку подлинности, необходимо начать с самого конкретного правила , влияющего на Jisun, а затем перейти к менее конкретным правилам, которые разрешают всем другим пользователям, прошедшим проверку подлинности, но запрещают всех анонимных пользователей. Следующие правила авторизации URL-адресов реализуют эту политику, сначала запрещая Jisun, а затем запрещая анонимных пользователей. Любому пользователю, прошедшему проверку подлинности, кроме Jisun, будет предоставлен доступ, так как ни один из этих <deny> операторов не будет совпадать.

<authorization>
 <deny users="Jisun" />
 <deny users="?" />
</authorization>

Шаг 2. Исправление рабочего процесса для неавторизованных пользователей, прошедших проверку подлинности

Как мы уже говорили ранее в этом руководстве в разделе Просмотр рабочего процесса авторизации URL-адресов, каждый раз, когда происходит несанкционированный запрос, UrlAuthorizationModule запрос прерывается и возвращается состояние HTTP 401 Unauthorized. Это состояние 401 изменяется в FormsAuthenticationModule состояние перенаправления 302, которое отправляет пользователя на страницу входа. Этот рабочий процесс выполняется при любом несанкционированном запросе, даже если пользователь прошел проверку подлинности.

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

Начните с создания новой страницы ASP.NET в корневой папке веб-приложения с именем UnauthorizedAccess.aspx. Не забудьте связать эту страницу со страницей Site.master master. После создания этой страницы удалите элемент управления Контент, который ссылается на LoginContent ContentPlaceHolder, чтобы отображалось содержимое страницы master по умолчанию. Затем добавьте сообщение с описанием ситуации, а именно о том, что пользователь пытался получить доступ к защищенному ресурсу. После добавления такого сообщения UnauthorizedAccess.aspx декларативная разметка страницы должна выглядеть примерно так:

<%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeFile="UnauthorizedAccess.aspx.cs" Inherits="UnauthorizedAccess"
Title="Untitled Page" %>

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent"
Runat="Server">
 <h2>Unauthorized Access</h2>
 <p>
 You have attempted to access a page that you are not authorized to view.
 </p>
 <p>
 If you have any questions, please contact the site administrator.
 </p>
</asp:Content>

Теперь необходимо изменить рабочий процесс, чтобы при выполнении несанкционированного запроса пользователем, прошедшим проверку подлинности, он отправлялся на UnauthorizedAccess.aspx страницу, а не на страницу входа. Логика, перенаправляющая несанкционированные запросы на страницу входа, находится в закрытом методе FormsAuthenticationModule класса , поэтому мы не можем настроить это поведение. Однако мы можем добавить собственную логику на страницу входа, которая при необходимости перенаправляет пользователя на UnauthorizedAccess.aspx.

FormsAuthenticationModule Когда объект перенаправляет несанкционированного посетителя на страницу входа, он добавляет запрошенный, несанкционированный URL-адрес в строку запроса с именем ReturnUrl. Например, если несанкционированный пользователь попытался посетить OnlyTito.aspx, FormsAuthenticationModule объект перенаправит его на Login.aspx?ReturnUrl=OnlyTito.aspx. Таким образом, если на страницу входа достигает пользователь, прошедший проверку подлинности, с помощью строки запроса, включающей ReturnUrl параметр , мы знаем, что этот пользователь, не прошедший проверку подлинности, просто пытался перейти на страницу, которую ей не разрешено просматривать. В этом случае мы хотим перенаправить ее на UnauthorizedAccess.aspx.

Для этого добавьте следующий код в обработчик событий страницы Page_Load входа:

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        if (Request.IsAuthenticated && !string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))
        // This is an unauthorized, authenticated request...
        Response.Redirect("~/UnauthorizedAccess.aspx");
    }
}

Приведенный выше код перенаправляет на страницу прошедших проверку подлинности неавторизованных пользователей UnauthorizedAccess.aspx . Чтобы увидеть эту логику в действии, посетите сайт в качестве анонимного посетителя и щелкните ссылку Создание учетных записей пользователей в левом столбце. Вы откроете страницу ~/Membership/CreatingUserAccounts.aspx , на которой на шаге 1 мы настроили разрешение доступа только к Tito. Так как анонимные пользователи FormsAuthenticationModule запрещены, компонент перенаправляет нас обратно на страницу входа.

На этом этапе мы анонимны, поэтому Request.IsAuthenticated возвращает и false не перенаправляется на UnauthorizedAccess.aspx. Вместо этого отображается страница входа. Войдите как пользователь, отличный от Tito, например Брюс. После ввода соответствующих учетных данных страница входа перенаправляет нас обратно на страницу ~/Membership/CreatingUserAccounts.aspx. Однако, так как эта страница доступна только Tito, мы не имеем разрешения на ее просмотр и быстро возвращаемся на страницу входа. Однако Request.IsAuthenticated на этот раз возвращается trueReturnUrl параметр querystring существует), поэтому мы перенаправляемся на страницу UnauthorizedAccess.aspx .

Проверка подлинности, неавторизованные пользователи перенаправляются в UnauthorizedAccess.aspx

Рис. 6. Проверка подлинности, перенаправление UnauthorizedAccess.aspx неавторизованных пользователей (щелкните для просмотра полноразмерного изображения)

Этот настраиваемый рабочий процесс обеспечивает более разумный и простой пользовательский интерфейс, за счет короткого замыкания цикла, показанного на рис. 2.

Шаг 3. Ограничение функциональных возможностей на основе вошедшего в систему пользователя

Авторизация по URL-адресу упрощает указание грубых правил авторизации. Как мы видели на шаге 1, с авторизацией ПО URL-адреса можно кратко указать, какие удостоверения разрешены, а какие из них запрещено просматривать определенную страницу или все страницы в папке. Однако в некоторых сценариях может потребоваться разрешить всем пользователям посещать страницу, но ограничить функциональность страницы в зависимости от того, какой пользователь ее посещает.

Рассмотрим случай с веб-сайтом электронной коммерции, который позволяет аутентифицированным посетителям просматривать свои продукты. Когда анонимный пользователь посещает страницу продукта, он видит только сведения о продукте и не получает возможность оставить отзыв. Однако пользователь, прошедший проверку подлинности, находящийся на той же странице, увидит интерфейс проверки. Если прошедший проверку пользователь еще не проверил этот продукт, интерфейс позволит ему отправить отзыв; в противном случае будет отображаться ранее отправленная проверка. Чтобы сделать этот сценарий еще дальше, на странице продукта могут отображаться дополнительные сведения и предлагаться расширенные функции для тех пользователей, которые работают в компании электронной коммерции. Например, на странице продукта может быть указан список запасов на складе и включить варианты изменения цены и описания продукта при посещении сотрудником.

Такие правила тонкой авторизации могут быть реализованы декларативно или программно (или с помощью некоторого сочетания этих двух). В следующем разделе мы посмотрим, как реализовать тонкую авторизацию с помощью элемента управления LoginView. После этого мы рассмотрим программные методы. Прежде чем мы рассмотрим применение правил тонкой авторизации, сначала необходимо создать страницу, функциональность которой зависит от того, кто ее посещает.

Давайте создадим страницу со списком файлов в определенном каталоге в GridView. Наряду со списком имени, размера и других сведений для каждого файла GridView будет включать два столбца LinkButtons: один с заголовком Представление и другой с именем Delete. Если щелкнуть элемент View LinkButton, отобразится содержимое выбранного файла; Если щелкнуть элемент Удалить linkButton, файл будет удален. Сначала создадим эту страницу таким образом, чтобы ее функции просмотра и удаления были доступны всем пользователям. В разделах Использование элемента управления LoginView и Программное ограничение функциональных возможностей мы посмотрим, как включить или отключить эти функции в зависимости от того, какой пользователь посещает страницу.

Примечание

На странице ASP.NET, который мы собираемся создать, для отображения списка файлов используется элемент управления GridView. Так как в этой серии учебников основное внимание уделяется проверке подлинности на основе форм, авторизации, учетным записям пользователей и ролям, я не хочу тратить слишком много времени на обсуждение внутренней работы элемента управления GridView. Хотя в этом руководстве содержатся пошаговые инструкции по настройке этой страницы, в нем не рассматриваются сведения о том, почему были сделаны определенные варианты или какое влияние на отображаемые выходные данные оказывают определенные свойства. Подробные сведения об элементе управления GridView см. в статье Работа с данными в серии учебников ASP.NET 2.0 .

Начните с UserBasedAuthorization.aspx открытия файла в папке Membership и добавления элемента управления GridView на страницу с именем FilesGrid. В смарт-теге GridView щелкните ссылку Изменить столбцы, чтобы открыть диалоговое окно Поля. Здесь снимите флажок Автоматически создавать поля в левом нижнем углу. Затем добавьте кнопки Выбрать, Удалить и два Поля BoundField в левом верхнем углу (кнопки Выбрать и Удалить можно найти в типе CommandField). Задайте для свойства кнопки SelectText Выбрать значение Вид, а для первых свойств BoundField HeaderText и — DataField Имя. Присвойте свойству BoundField HeaderText значение Size в байтах, свойству DataField Length, DataFormatString свойству HtmlEncode — значение {0:N0} False.

После настройки столбцов GridView нажмите кнопку ОК, чтобы закрыть диалоговое окно Поля. В окне Свойства задайте свойству GridView DataKeyNames значение FullName. На этом этапе декларативная разметка GridView должна выглядеть следующим образом:

<asp:GridView ID="FilesGrid" DataKeyNames="FullName" runat="server" AutoGenerateColumns="False">
 <Columns>
 <asp:CommandField SelectText="View" ShowSelectButton="True"/>
 <asp:CommandField ShowDeleteButton="True" />
 <asp:BoundField DataField="Name" HeaderText="Name" />
 <asp:BoundField DataField="Length" DataFormatString="{0:N0}"
 HeaderText="Size in Bytes" HtmlEncode="False" />
 </Columns>
</asp:GridView>

Создав разметку GridView, мы готовы написать код, который будет извлекать файлы в определенном каталоге и привязывать их к GridView. Добавьте следующий код в обработчик событий страницы Page_Load :

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        string appPath = Request.PhysicalApplicationPath;
        DirectoryInfo dirInfo = new DirectoryInfo(appPath);

        FileInfo[] files = dirInfo.GetFiles();

        FilesGrid.DataSource = files;
        FilesGrid.DataBind();
    }
}

Приведенный выше код использует DirectoryInfo класс для получения списка файлов в корневой папке приложения. МетодGetFiles() возвращает все файлы в каталоге в виде массива FileInfo объектов, который затем привязывается к GridView. Объект FileInfo имеет ряд свойств, таких как Name, Lengthи , среди IsReadOnlyпрочего. Как видно из декларативной разметки, GridView отображает только Name свойства и Length .

Примечание

Классы DirectoryInfo и FileInfo находятся в System.IO пространстве имен. Поэтому вам потребуется либо предварить имена этих классов именами пространств имен, либо импортировать пространство имен в файл класса (с помощью using System.IO).

Посетите эту страницу через браузер. Отобразится список файлов, находящихся в корневом каталоге приложения. Если щелкнуть любой из ссылок View или Delete LinkButtons, произойдет обратная связь, но никаких действий не будет, так как мы еще не создали необходимые обработчики событий.

GridView выводит список файлов в корневом каталоге веб-приложения.

Рис. 7. GridView выводит список файлов в корневом каталоге веб-приложения (щелкните для просмотра полноразмерного изображения)

Нам нужно средство для отображения содержимого выбранного файла. Вернитесь в Visual Studio и добавьте элемент TextBox с именем FileContents над GridView. Задайте для свойства TextMode значение , MultiLine а свойства Columns и Rows — 95 % и 10 соответственно.

<asp:TextBox ID="FileContents" runat="server" Rows="10"
TextMode="MultiLine" Width="95%"></asp:TextBox>

Затем создайте обработчик событий для события GridView SelectedIndexChanged и добавьте следующий код:

protected void FilesGrid_SelectedIndexChanged(object sender, EventArgs e)
{
    // Open the file and display it
    string fullFileName = FilesGrid.SelectedValue.ToString();
    string contents = File.ReadAllText(fullFileName);
    FileContents.Text = contents;
}

Этот код использует свойство GridView SelectedValue для определения полного имени выбранного файла. На внутренней DataKeys территории ссылка на коллекцию используется для получения SelectedValue, поэтому необходимо задать для свойства GridView DataKeyNames значение Name, как описано ранее на этом шаге. КлассFile используется для считывания содержимого выбранного файла в строку, которая затем назначается свойству FileContents TextBoxText, тем самым отображая содержимое выбранного файла на странице.

Содержимое выбранного файла отображается в элементе TextBox

Рис. 8. Содержимое выбранного файла отображается в текстовом поле (щелкните для просмотра полноразмерного изображения)

Примечание

Если просмотреть содержимое файла, содержащего разметку HTML, а затем попытаться просмотреть или удалить файл, появится сообщение об ошибке HttpRequestValidationException . Это происходит потому, что при обратной отправке содержимое TextBox отправляется обратно на веб-сервер. По умолчанию ASP.NET вызывает ошибку HttpRequestValidationException при обнаружении потенциально опасного содержимого обратной передачи, например HTML-разметки. Чтобы отключить эту ошибку, отключите проверку запроса для страницы, добавив ValidateRequest="false" в директиву @Page . Дополнительные сведения о преимуществах проверки запросов, а также о том, какие меры предосторожности следует принимать при ее отключении, см. в статье Проверка запросов — предотвращение атак скриптов.

Наконец, добавьте обработчик событий со следующим кодом для события GridViewRowDeleting:

protected void FilesGrid_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
    string fullFileName = FilesGrid.DataKeys[e.RowIndex].Value.ToString();
    FileContents.Text = string.Format("You have opted to delete {0}.", fullFileName);

    // To actually delete the file, uncomment the following line
    // File.Delete(fullFileName);
}

Код просто отображает полное имя удаляемого файла в Элементе FileContents TextBox без фактического удаления файла.

Нажатие кнопки

Рис. 9. Нажатие кнопки "Удалить" не приводит к фактическому удалению файла (щелкните для просмотра полноразмерного изображения)

На шаге 1 мы настроили правила авторизации URL-адресов, чтобы запретить анонимным пользователям просматривать страницы в папке Membership . Чтобы лучше продемонстрировать тонкую проверку подлинности, давайте разрешим анонимным пользователям посещать страницу UserBasedAuthorization.aspx , но с ограниченной функциональностью. Чтобы открыть эту страницу для доступа всех пользователей, добавьте следующий <location> элемент в Web.config файл в папке Membership :

<location path="UserBasedAuthorization.aspx">
 <system.web>
 <authorization>
 <allow users="*" />
 </authorization>
 </system.web>
</location>

После добавления этого <location> элемента проверьте новые правила авторизации URL-адресов, выйдя из сайта. Как анонимный пользователь вам должно быть разрешено посещать страницу UserBasedAuthorization.aspx .

В настоящее время любой прошедший проверку подлинности или анонимный пользователь может посетить страницу UserBasedAuthorization.aspx и просмотреть или удалить файлы. Давайте сделаем так, чтобы только пользователи, прошедшие проверку подлинности, могли просматривать содержимое файла, а только Tito — удалять файл. Такие правила тонкой авторизации можно применять декларативно, программно или с помощью сочетания обоих методов. Давайте воспользуемся декларативным подходом, чтобы ограничить пользователей, которые могут просматривать содержимое файла; Мы будем использовать программный подход, чтобы ограничить пользователей, которые могут удалять файл.

Использование элемента управления LoginView

Как мы уже видели в предыдущих руководствах, элемент управления LoginView полезен для отображения различных интерфейсов для прошедших проверку подлинности и анонимных пользователей и предоставляет простой способ скрыть функции, недоступные анонимным пользователям. Так как анонимные пользователи не могут просматривать или удалять файлы, необходимо отображать FileContents элемент TextBox только при посещении страницы пользователем, прошедшим проверку подлинности. Для этого добавьте элемент управления LoginView на страницу, назовите его LoginViewForFileContentsTextBoxи переместите FileContents декларативную разметку TextBox в элемент управления LoggedInTemplateLoginView .

<asp:LoginView ID=" LoginViewForFileContentsTextBox " runat="server">
 <LoggedInTemplate>
 <p>
 <asp:TextBox ID="FileContents" runat="server" Rows="10"
 TextMode="MultiLine" Width="95%"></asp:TextBox>
 </p>
 </LoggedInTemplate>
</asp:LoginView>

Веб-элементы управления в шаблонах LoginView больше не доступны напрямую из класса кода программной части. Например, обработчики FilesGrid событий GridView SelectedIndexChanged и RowDeleting в настоящее время ссылались на FileContents элемент управления TextBox с помощью следующего кода:

FileContents.Text = text;

Однако этот код больше недействителен. При перемещении FileContents элемента TextBox в LoggedInTemplate элемент TextBox невозможно получить прямой доступ. Вместо этого мы должны использовать метод для программной FindControl("controlId") ссылки на элемент управления . Обновите обработчики FilesGrid событий, чтобы они ссылались на TextBox следующим образом:

TextBox FileContentsTextBox = LoginViewForFileContentsTextBox.FindControl("FileContents") as TextBox;
FileContentsTextBox.Text = text;

После перемещения элемента TextBox в LoginView LoggedInTemplate и обновления кода страницы для ссылки на TextBox с помощью FindControl("controlId") шаблона посетите страницу от имени анонимного пользователя. Как показано на рисунке FileContents 10, элемент TextBox не отображается. Однако элемент View LinkButton по-прежнему отображается.

Элемент управления LoginView отображает только элемент Управления FileContents TextBox для пользователей, прошедших проверку подлинности

Рис. 10. Элемент управления LoginView отображает только FileContents элемент TextBox для пользователей, прошедших проверку подлинности (щелкните для просмотра полноразмерного изображения)

Один из способов скрыть кнопку Вид для анонимных пользователей — преобразовать поле GridView в TemplateField. При этом будет создан шаблон, содержащий декларативную разметку для элемента View LinkButton. Затем мы можем добавить элемент управления LoginView в TemplateField и поместить LinkButton в LoginView LoggedInTemplate, тем самым скрывая кнопку Вид от анонимных посетителей. Для этого щелкните ссылку Изменить столбцы в смарт-теге GridView, чтобы открыть диалоговое окно Поля. Затем нажмите кнопку Выбрать в списке в левом нижнем углу и щелкните ссылку Преобразовать это поле в TemplateField. Это приведет к изменению декларативной разметки поля из:

<asp:CommandField SelectText="View" ShowSelectButton="True"/>

В:

<asp:TemplateField ShowHeader="False">
 <ItemTemplate>
 <asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="False"
 CommandName="Select" Text="View"></asp:LinkButton>
 </ItemTemplate>
</asp:TemplateField>

На этом этапе можно добавить LoginView в TemplateField. Следующая разметка отображает элемент View LinkButton только для пользователей, прошедших проверку подлинности.

<asp:TemplateField ShowHeader="False">
 <ItemTemplate>
 <asp:LoginView ID="LoginView1" runat="server">
 <LoggedInTemplate>
 <asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="False"
 CommandName="Select" Text="View"></asp:LinkButton>
 </LoggedInTemplate>
 </asp:LoginView>
 </ItemTemplate>
</asp:TemplateField>

Как показано на рисунке 11, конечный результат не очень хороший, так как столбец View по-прежнему отображается, несмотря на то, что элементы LinkButtons в столбце скрыты. В следующем разделе мы рассмотрим, как скрыть весь столбец GridView (а не только LinkButton).

Элемент управления LoginView скрывает кнопки просмотра ссылок для анонимных посетителей

Рис. 11. Элемент управления LoginView скрывает кнопки просмотра ссылок для анонимных посетителей (щелкните для просмотра полноразмерного изображения)

Программное ограничение функциональных возможностей

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

Чтобы ограничить функциональные возможности программными средствами, необходимо выполнить две задачи:

  1. Определите, может ли пользователь, посещая страницу, получить доступ к функциональным возможностям;
  2. Программно измените пользовательский интерфейс в зависимости от того, имеет ли пользователь доступ к рассматриваемой функциональности.

Чтобы продемонстрировать применение этих двух задач, давайте разрешим Tito удалять файлы из GridView. Наша первая задача заключается в том, чтобы определить, является ли тито посещать страницу. После определения необходимо скрыть (или отобразить) столбец GridView Delete. Столбцы GridView доступны через его Columns свойство; столбец отображается только в том случае, если его Visible свойству true присвоено значение (значение по умолчанию).

Добавьте следующий код в Page_Load обработчик событий перед привязкой данных к GridView:

// Is this Tito visiting the page?
string userName = User.Identity.Name;
if (string.Compare(userName, "Tito", true) == 0)
    // This is Tito, SHOW the Delete column
    FilesGrid.Columns[1].Visible = true;
else
    // This is NOT Tito, HIDE the Delete column
    FilesGrid.Columns[1].Visible = false;

Как мы обсуждали в руководстве Общие сведения о проверке подлинности на основе форм , User.Identity.Name возвращает имя удостоверения. Это соответствует имени пользователя, введенного в элементе управления Вход. Если страницу посещает Tito, свойству второго столбца Visible GridView присваивается значение true; в противном случае ему присваивается значение false. Результатом является то, что когда кто-то, кроме Тито, посещает страницу, другой пользователь, прошедший проверку подлинности, или анонимный пользователь, столбец Delete не отображается (см. рис. 12); однако при посещении страницы Tito отображается столбец Delete (см. рис. 13).

Столбец delete не отображается при посещении кем-то, кроме Тито (например, Брюс)

Рис. 12. Удаление столбца не отображается при посещении кем-то, кроме Тито (например, Брюса) (щелкните для просмотра полноразмерного изображения)

Для Tito отображается столбец delete

Рис. 13. Удаление столбца отрисовывается для Tito (щелкните для просмотра полноразмерного изображения)

Шаг 4. Применение правил авторизации к классам и методам

На шаге 3 мы запретили анонимным пользователям просматривать содержимое файла и запретили удалять файлы всем пользователям, кроме Тито. Это было сделано путем скрытия связанных элементов пользовательского интерфейса для несанкционированных посетителей с помощью декларативных и программных методов. В нашем простом примере правильно скрыть элементы пользовательского интерфейса было просто, но как насчет более сложных сайтов, где может быть много различных способов выполнения одной и той же функции? Что произойдет, если мы забудем скрыть или отключить все применимые элементы пользовательского интерфейса при ограничении этой функции неавторизованными пользователями?

Простой способ убедиться, что неавторизованный пользователь не сможет получить доступ к определенной функциональности, заключается в том, чтобы украсить этот класс или метод атрибутомPrincipalPermission . Когда среда выполнения .NET использует класс или выполняет один из его методов, она проверяет, имеет ли текущий контекст безопасности разрешение на использование класса или выполнение метода . Атрибут PrincipalPermission предоставляет механизм, с помощью которого можно определить эти правила.

Давайте продемонстрируем использование атрибута PrincipalPermissionSelectedIndexChanged в обработчиках событий GridView и RowDeleting для запрета выполнения анонимными пользователями и пользователями, не другими Tito, соответственно. Все, что нам нужно сделать, это добавить соответствующий атрибут на вершину каждого определения функции:

[PrincipalPermission(SecurityAction.Demand, Authenticated=true)]
protected void FilesGrid_SelectedIndexChanged(object sender, EventArgs e)
{
    ...
}

[PrincipalPermission(SecurityAction.Demand, Name="Tito")]
protected void FilesGrid_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
    ...
}

Атрибут обработчика SelectedIndexChanged событий определяет, что только пользователи, прошедшие проверку подлинности, могут выполнять обработчик событий, где в качестве атрибута обработчика RowDeleting событий выполнение ограничивается Tito.

Если каким-либо образом пользователь, отличный от Tito, пытается выполнить RowDeleting обработчик событий или пользователь, не прошедший проверку подлинности, пытается выполнить SelectedIndexChanged обработчик событий, среда выполнения .NET вызовет .SecurityException

Если контекст безопасности не авторизован для выполнения метода, создается исключение SecurityException.

Рис. 14. Если контекст безопасности не авторизован для выполнения метода, SecurityException возникает исключение (щелкните для просмотра полноразмерного изображения)

Примечание

Чтобы разрешить нескольким контекстам безопасности доступ к классу или методу, украсите класс или метод атрибутом PrincipalPermission для каждого контекста безопасности. То есть, чтобы позволить Тито и Брюсу выполнять RowDeleting обработчик событий, добавьте дваPrincipalPermission атрибута:

[PrincipalPermission(SecurityAction.Demand, Name="Tito")]

[PrincipalPermission(SecurityAction.Demand, Name="Bruce")]

Помимо ASP.NET страниц, многие приложения также имеют архитектуру, которая включает в себя различные уровни, такие как бизнес-логика и уровни доступа к данным. Эти уровни обычно реализуются как библиотеки классов и предлагают классы и методы для выполнения функций, связанных с бизнес-логикой и данными. Атрибут PrincipalPermission полезен для применения правил авторизации к этим уровням.

Дополнительные сведения об использовании атрибута PrincipalPermission для определения правил авторизации для классов и методов см. в записи блога Скотта ГатриДобавление правил авторизации в уровни бизнеса и данных с помощью PrincipalPermissionAttributes.

Сводка

В этом руководстве мы рассмотрели, как применять правила авторизации на основе пользователей. Мы начали с взгляда на ASP. Платформа авторизации URL-адресов NET. При каждом запросе подсистема UrlAuthorizationModule ASP.NET проверяет правила авторизации URL-адресов, определенные в конфигурации приложения, чтобы определить, авторизовано ли удостоверение для доступа к запрошенным ресурсам. Короче говоря, авторизация ПО URL-адреса позволяет легко указать правила авторизации для определенной страницы или для всех страниц в определенном каталоге.

Платформа авторизации ПО URL-адреса применяет правила авторизации постранично. При авторизации ПО URL-адреса запрашивающее удостоверение авторизовано для доступа к определенному ресурсу или нет. Однако во многих сценариях требуются более детализированные правила авторизации. Вместо того чтобы определять, кому разрешен доступ к странице, может потребоваться разрешить всем пользователям доступ к странице, но показать разные данные или предложить различные функции в зависимости от того, кто посещает страницу. Авторизация на уровне страниц обычно включает скрытие определенных элементов пользовательского интерфейса, чтобы предотвратить доступ неавторизованных пользователей к запрещенным функциям. Кроме того, атрибуты можно использовать для ограничения доступа к классам и выполнения их методов для определенных пользователей.

Счастливого программирования!

Дополнительные материалы

Дополнительные сведения о темах, рассмотренных в этом руководстве, см. в следующих ресурсах:

Об авторе

Скотт Митчелл(Scott Mitchell), автор нескольких книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часах. Скотт может быть доступен в mitchell@4guysfromrolla.com или через его блог по адресу http://ScottOnWriting.NET.

Особая благодарность

Эта серия учебников была рассмотрена многими полезными рецензентами. Хотите просмотреть предстоящие статьи MSDN? Если да, опустите мне строку на mitchell@4GuysFromRolla.com.