Мне нужно сделать что-то довольно простое: в моем приложении ASP.NET MVC я хочу установить пользовательский IIdentity / IPrincipal. В зависимости от того, что проще / больше подходит. Я хочу расширить значение по умолчанию, чтобы я мог вызвать что-то вроде User.Identity.Id
и User.Identity.Role
. Ничего особенного, только некоторые дополнительные свойства.
Я прочитал тонны статей и вопросов, но чувствую, что делаю это сложнее, чем есть на самом деле. Я думал, что это будет легко. Если пользователь входит в систему, я хочу установить свой IIdentity. Вот я и подумал, я буду внедрять Application_PostAuthenticateRequest
в свой global.asax. Однако это вызывается при каждом запросе, и я не хочу делать вызов базы данных при каждом запросе, который будет запрашивать все данные из базы данных и помещать в пользовательский объект IPrincipal. Это также кажется очень ненужным, медленным и не в том месте (делая там вызовы из базы данных), но я могу ошибаться. Или откуда еще эти данные?
Поэтому я подумал, что всякий раз, когда пользователь входит в систему, я могу добавить в сеанс некоторые необходимые переменные, которые я добавляю в пользовательский IIdentity в Application_PostAuthenticateRequest
обработчике событий. Тем не менее, мой Context.Session
находится null
там, так что это тоже не путь.
Я работаю над этим уже целый день и чувствую, что что-то упустил. Это не должно быть слишком сложно, верно? Я также немного смущен всеми (полу) связанными вещами, которые идут с этим. MembershipProvider
, MembershipUser
, RoleProvider
, ProfileProvider
, IPrincipal
, IIdentity
, FormsAuthentication
.... Am Я единственный, кто находит все это очень запутанным?
Если бы кто-то мог сказать мне простое, элегантное и эффективное решение для хранения некоторых дополнительных данных на IIdentity без всего лишнего запаха ... это было бы здорово! Я знаю, что есть аналогичные вопросы по SO, но, если мне нужен ответ, я должен был упустить это из виду.
MemberShip...
,Principal
,Identity
. ASP.NET должен упростить, упростить и максимально использовать два подхода к аутентификации.Ответы:
Вот как я это делаю.
Я решил использовать IPrincipal вместо IIdentity, потому что это означает, что мне не нужно реализовывать как IIdentity, так и IPrincipal.
Создать интерфейс
CustomPrincipal
CustomPrincipalSerializeModel - для сериализации пользовательской информации в поле пользовательских данных в объекте FormsAuthenticationTicket.
Метод входа в систему - настройка куки с пользовательской информацией
Global.asax.cs - чтение cookie и замена объекта HttpContext.User, это делается путем переопределения PostAuthenticateRequest
Доступ в Razor Views
и в коде:
Я думаю, что код не требует пояснений. Если это не так, дайте мне знать.
Кроме того, чтобы сделать доступ еще проще, вы можете создать базовый контроллер и переопределить возвращенный объект User (HttpContext.User):
а затем для каждого контроллера:
что позволит вам получить доступ к настраиваемым полям в коде следующим образом:
Но это не будет работать изнутри. Для этого вам нужно создать собственную реализацию WebViewPage:
Сделайте его типом страницы по умолчанию в Views / web.config:
и в представлениях, вы можете получить к нему доступ, как это:
источник
Thread.CurrentPrincipal
наApplication_PostAuthenticateRequest
для него , чтобы работать , поскольку он не полагается наHttpContext.Current.User
FormsAuthentication.SignOut();
прекрасно работает для меня.Я не могу говорить напрямую о ASP.NET MVC, но для ASP.NET Web Forms хитрость заключается в создании
FormsAuthenticationTicket
и зашифровать его в файл cookie после проверки подлинности пользователя. Таким образом, вам нужно будет вызвать базу данных только один раз (или AD, или что-то еще, что вы используете для выполнения вашей аутентификации), и каждый последующий запрос будет аутентифицироваться на основе тикета, хранящегося в cookie.Хорошая статья на эту тему:
http://www.ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html(неработающая ссылка)Редактировать:
Поскольку ссылка выше не работает, я бы порекомендовал решение LukeP в его ответе выше: https://stackoverflow.com/a/10524305 - Я бы также предложил изменить принятый ответ на этот.
Изменить 2: Альтернатива для неработающей ссылки: https://web.archive.org/web/20120422011422/http://ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html
источник
Cache
качествеSession
замены, чтобы сохранить данные на сервере. Может кто-нибудь сказать мне, если это ошибочный подход?Вот пример, чтобы сделать работу. bool isValid устанавливается путем просмотра некоторого хранилища данных (скажем, вашей пользовательской базы данных). UserID - это просто идентификатор, который я поддерживаю. Вы можете добавить дополнительную информацию, такую как адрес электронной почты, к данным пользователя.
в golbal asax добавьте следующий код, чтобы получить вашу информацию
Когда вы собираетесь использовать информацию позже, вы можете получить доступ к своему пользовательскому принципалу следующим образом.
это позволит вам получить доступ к пользовательской информации пользователя.
источник
MVC предоставляет вам метод OnAuthorize, который зависает от классов вашего контроллера. Или вы можете использовать фильтр пользовательских действий для выполнения авторизации. MVC делает это довольно легко сделать. Я разместил пост в блоге об этом здесь. http://www.bradygaster.com/post/custom-authentication-with-mvc-3.0
источник
Вот решение, если вам нужно подключить некоторые методы к @User для использования в ваших представлениях. Нет решения для какой-либо серьезной настройки членства, но если исходный вопрос был необходим только для одних мнений, то, возможно, этого было бы достаточно. Нижеследующее использовалось для проверки переменной, возвращенной из authorizefilter, использовалось для проверки, должны ли некоторые ссылки быть здесь или нет (не для какой-либо логики авторизации или предоставления доступа).
Затем просто добавьте ссылку в области web.config и назовите ее, как показано ниже.
источник
Основываясь на ответе LukeP , добавьте несколько методов для настройки
timeout
иrequireSSL
сотрудничестваWeb.config
.Ссылки ссылки
Модифицированные коды LukeP
1, установить
timeout
на основеWeb.Config
. FormsAuthentication.Timeout получит значение тайм - аута, который определен в web.config. Я обернул следующее, чтобы быть функцией, которая возвращаетticket
обратно.2. Настройте cookie-файлы, чтобы они были безопасными или нет, в зависимости от
RequireSSL
конфигурации.источник
Итак, я серьезный хранитель криптовалют, перетаскивая этот очень старый вопрос, но есть гораздо более простой подход к этому, который был затронут @Baserz выше. И это использовать комбинацию методов C # Extension и кэширования (НЕ использовать сессию).
Фактически, Microsoft уже предоставила ряд таких расширений в
Microsoft.AspNet.Identity.IdentityExtensions
пространстве имен. Например,GetUserId()
это метод расширения, который возвращает идентификатор пользователя. Существует такжеGetUserName()
иFindFirstValue()
, который возвращает претензии на основе IPrincipal.Таким образом, вам нужно только включить пространство имен, а затем вызвать,
User.Identity.GetUserName()
чтобы получить имя пользователя в соответствии с настройками ASP.NET Identity.Я не уверен, что это кэшируется, так как более старая идентификация ASP.NET не является открытым исходным кодом, и я не удосужился ее перепроектировать. Однако, если это не так, вы можете написать свой собственный метод расширения, который будет кэшировать этот результат в течение определенного периода времени.
источник
IsUserAdministrator
илиUserEmail
т. Д.? Ты думаешьHttpRuntime.Cache
?В качестве дополнения к коду LukeP для пользователей веб-форм (не MVC), если вы хотите упростить доступ к коду позади ваших страниц, просто добавьте приведенный ниже код на базовую страницу и создайте базовую страницу на всех своих страницах:
Таким образом, в вашем коде вы можете просто получить доступ к:
Чего мне не хватает в сценарии веб-формы, так это как получить такое же поведение в коде, не привязанном к странице, например, в модулях http, следует ли мне всегда добавлять приведение в каждый класс или есть более разумный способ получить это?
Спасибо за ваши ответы и поблагодарить LukeP , так как я использовал свои примеры в качестве базы для моего пользовательского пользователя (который теперь имеет
User.Roles
,User.Tasks
,User.HasPath(int)
,User.Settings.Timeout
и многие другие приятные вещи)источник
Я попробовал решение, предложенное LukeP, и обнаружил, что оно не поддерживает атрибут Authorize. Итак, я немного изменил его.
И, наконец, в Global.asax.cs
Теперь я могу получить доступ к данным в представлениях и контроллерах, просто позвонив
Чтобы выйти, я просто звоню
где AuthManager
источник