2009-04-24 2 views
4

В настоящее время я изучаю альтернативные решения стандартной конфигурации авторизации страницы в asp.net.Авторизация страницы ASP.NET ... Как вы это делаете?

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

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

Любые предложения о том, как это сделать? Существуют ли какие-либо решения, интегрирующие авторизацию azman и asp.net? Есть ли какие-либо другие стандартные решения, о которых я должен знать?

ответ

6

я в огромном заявке, имеющей множество различных разрешений и различных ролей нечто вроде следующего [У меня нет кода здесь, так что я просто пытаюсь воссоздать его здесь]:

я впервые реализовал класс под названием SecuredPage следующим образом:


public class SecuredPage : System.Web.UI.Page 
{ 
    // Those Permissions are mandatory, so user needs to have all of them 
    public List MandatoryPermissions { get; set; } 

    // Those Permissions are optional, so if the user have at least one of them, he can access 
    public List OptionalPermissions { get; set; } 

    protected override void OnLoad(EventArgs e) 
    { 
     MyUser loggedUser = (MyUser) this.User; 

     base.OnLoad(e); 

     foreach (Permission mandatoryPermission in MandatoryPermissions) 
     { 
      // if the user don't have permission, we can redirect him 
      if (!loggedUser.HasPermission(mandatoryPermission)) 
      { 
       RedirectToDontHaveAccess(); 
       break; 
      } 
     } 

     bool hasAccessToThePage = false; 

     foreach (Permission optionalPermission in OptionalPermissions) 
     { 
      // If the user has at least one of the permissions, he can access 
      if (loggedUser.HasPermission(optionalPermission)) 
      { 
       hasAccessToThePage = true; 
      } 
     } 

     if (!hasAccessToThePage) 
     { 
      RedirectToDontHaveAccess(); 
     } 

    } 

    private void RedirectToDontHaveAccess() 
    { 
     throw new NotImplementedException(); 
    } 
} 

Это будет моя базовая страница для всех страниц, которым нужны разрешения для доступа. MandatoryPermissions - это разрешения, которые пользователь ДОЛЖЕН иметь для доступа к этой странице, а OptionalPermissions - это разрешения, для которых пользователю требуется хотя бы один из них для доступа к странице. Нет необходимости использовать обе страницы на каждой странице, потому что если у вас есть MandatoryPermissions, не имеет значения, есть ли у вас дополнительные или нет.

Разрешение является перечисление:


public enum Permission 
{ 
    // Usually this enum will replicate a domain table from the database 
    EditUser = 1, 
    SearchUserByUsername = 2, 
    SearchUserByEmail = 3 

} 

И MyUser является реализация MembershipUser:


public class MyUser : System.Web.Security.MembershipUser 
{ 
    internal bool HasPermission(Permission permission) 
    { 
     // 
     // TODO: Check on database if the user has the permission or not 
     // 
    } 
} 

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


public partial class EditUser : SecuredPage 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     MandatoryPermissions.Add(Permission.EditUser); 
    } 
} 

public partial class SearchUser : SecuredPage 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     OptionalPermissions.Add(Permission.SearchUserByUsername); 
     OptionalPermissions.Add(Permission.SearchUserByEmail); 
    } 
} 

ОК, пример поиска был не так хорош, но я думаю, что вы получите картину.

Идея состоит в том, что base.OnLoad(e); вызывается непосредственно перед проверкой разрешений, поэтому вам просто нужно заполнить разрешения в вашем Page_Load.

Я не уверен, если это лучшее решение, но я уверен, что это очень помогает :)

+0

Я реализовал MembershipProvider и RoleProvider. Мои вопросы - это то, как вы отделяете авторизацию от отдельных страниц. Я имею в виду, вы помещаете Roles.IsInRole («admin») на каждую из ваших страниц? Вы используете элементы местоположения web.config? Или у вас есть другой способ развязать его со страниц? – JohannesH

+0

Ах, хорошо, поэтому я отредактирую свой ответ, чтобы показать, как я обычно это делаю :) Всего секунду – homemdelata

+0

Да, подход типа «базовая страница» - это то, что мы делаем, - создайте базовую страницу, которая обрабатывает всю аутентификацию/доступ управление и т. д., а также несколько других функций, а затем наследовать отдельные страницы. –

0

Установили ли вы объекты GenericIdentity и IPrincipal во время вашего метода Application_AuthenticateRequest приложения?

В настоящее время мы используем наш домен для аутентификации и групп пользователей/ролей в базе данных SQL Server для обеспечения авторизации. Во время метода Application_AuthenticateRequest я собираю все эти данные и создаю на основе этого объекта FormsAuthenticationTicket.

Таким образом, теперь у меня есть доступ к ролям пользователя, выполняя в моем коде простую команду User.IsInRole («RoleX»), которая позволяет мне легко блокировать/разблокировать пользовательские элементы управления или даже выполнять простой ответ .Redirect() на страницу «Ошибка авторизации», если у них нет правильной авторизации.

Вот что мой метод AuthenticateRequest выглядит (VB.NET)

Sub Application_AuthenticateRequest(ByVal sender As Object, _ 
             ByVal e As EventArgs) 

     Dim formsAuthTicket As FormsAuthenticationTicket 
     Dim httpCook As HttpCookie 
     Dim objGenericIdentity As GenericIdentity 
     Dim objMyAppPrincipal As CustomPrincipal 
     Dim strRoles As String() 

     httpCook = Context.Request.Cookies.Get("authCookieEAF") 
     formsAuthTicket = FormsAuthentication.Decrypt(httpCook.Value) 
     objGenericIdentity = New GenericIdentity(formsAuthTicket.Name) 
     strRoles = formsAuthTicket.UserData.Split("|"c) 
     objMyAppPrincipal = New CustomPrincipal(objGenericIdentity, strRoles) 
     HttpContext.Current.User = objMyAppPrincipal  

    End Sub 

... и точно так же, вот что объект CustomPrincipal выглядит следующим образом:

Public Class CustomPrincipal 
    Implements IPrincipal 


    ''' <summary> 
    ''' Identity object of user. 
    ''' </summary> 
    ''' <remarks></remarks> 
    Private m_identity As IIdentity 

    ''' <summary> 
    ''' Roles(s) a user is a part of. 
    ''' </summary> 
    ''' <remarks></remarks> 
    Private m_roles As String() 

    ''' <summary> 
    ''' Name of user. 
    ''' </summary> 
    ''' <remarks></remarks> 
    Private m_userId As String 

    ''' <summary> 
    ''' Gets/Sets the user name. 
    ''' </summary> 
    ''' <value>m_userId</value> 
    ''' <returns>Current name of user.</returns> 
    ''' <remarks></remarks> 
    Public Property UserId() As String 
     Get 
     Return m_userId 
     End Get 
     Set(ByVal value As String) 
     m_userId = value 
     End Set 
    End Property 

    ''' <summary> 
    ''' Gets the identity object of the user. 
    ''' </summary> 
    ''' <value>m_identity</value> 
    ''' <returns>Current identity of user.</returns> 
    ''' <remarks></remarks> 
    Public ReadOnly Property Identity() As System.Security.Principal.IIdentity Implements System.Security.Principal.IPrincipal.Identity 
     Get 
     Return m_identity 
     End Get 
    End Property 

    ''' <summary> 
    ''' Full constructor. 
    ''' </summary> 
    ''' <param name="identity">Identity to use with Custom Principal.</param> 
    ''' <param name="roles">Roles for user.</param> 
    ''' <remarks>Identity object contains user name when building constructor.</remarks> 
    Public Sub New(ByVal identity As IIdentity, ByVal roles As String()) 

     m_identity = identity 
     m_roles = New String(roles.Length) {} 
     roles.CopyTo(m_roles, 0) 
     Array.Sort(m_roles) 
     m_userId = identity.Name 

    End Sub 

    ''' <summary> 
    ''' Determines if the current user is in the role specified. 
    ''' </summary> 
    ''' <param name="role">Role to test against.</param> 
    ''' <returns>Boolean variable indicating if role specified exists in user's m_roles array.</returns> 
    ''' <remarks></remarks> 
    Public Function IsInRole(ByVal role As String) As Boolean Implements System.Security.Principal.IPrincipal.IsInRole 

     Dim boolResults As Boolean 

     If Array.BinarySearch(m_roles, role) >= 0 Then 
     boolResults = True 
     Else 
     boolResults = False 
     End If 

     Return boolResults 

    End Function 

End Class 

Надеется, что это дает вам то, что вы необходимо формовать его в вашу среду.

+0

Мы имеем то же самое в наших приложениях, что мы просто используем собственный поставщик роли и поставщика членства для аутентификации и загрузки роли. Что я действительно хочу знать, вы тогда жестко программируете User.IsInRole («Admin») как первое, что находится в page_init на каждой странице вашего администратора. Или у вас есть другой способ развязки этой конфигурации? Я бы не хотел, чтобы на наши страницы вводились имена правил или названия правил azman. – JohannesH

+0

Я использую комбинацию авторизации web.config и мастер-шаблонов, чтобы сводить мой фактический код до минимума. У меня также есть несколько вспомогательных функций, таких как «IsAdminAuthorized» и «IsManagerAuthorized», которые выполняют сложные проверки, когда пользователи из нескольких разных ролей квалифицируются как администратор или менеджер. –

+0

Хорошо, мне кажется, что это слишком сложно. Мне не нравится жесткое кодирование. В принципе, мне кажется, мне нужно сделать что-то вроде модуля UrlAuthorization. – JohannesH

1

Как насчет отображения страниц на роли в базе данных, а затем дайте Masterpage проверить DB на PageLoad?

Смежные вопросы