2009-04-24 6 views
4

J'étudie actuellement des solutions alternatives à la configuration d'autorisation de page standard dans asp.net. La balise d'emplacement fonctionne bien si vous avez des répertoires de fichiers qui ont besoin de la même politique d'accès mais si vous avez beaucoup de politiques d'accès individuelles, la balise d'emplacement est pénible. Je pourrais rouler mon propre système d'authentification personnalisé mais si cela peut être évité, c'est probablement mieux.Autorisation de page ASP.NET ... Comment le faites-vous?

Actuellement, nous utilisons un système d'autorisation basé sur les permissions de type azman pour le contenu de la page, mais je n'ai pas encore trouvé un bon moyen d'intégrer cela à la sécurité de page standard.

Des suggestions sur comment faire cela? Existe-t-il des solutions intégrant l'autorisation de page azman et asp.net? Y a-t-il d'autres solutions standards dont je devrais être au courant?

Répondre

6

j'ai fait dans une application énorme d'avoir beaucoup de différentes autorisations et des rôles différents quelque chose comme [je n'ai pas le code ici, donc je vais essayer de le recréer ici]:

I Mis en œuvre une classe appelée SecuredPage comme suit:


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(); 
    } 
} 

Ce sera mon BasePage pour toutes les pages que les utilisateurs ont besoin d'autorisations d'accès. Les MandatoryPermissions sont des autorisations que l'utilisateur DOIT avoir tous pour accéder à la page et OptionalPermissions sont des autorisations que l'utilisateur a besoin d'au moins un d'entre eux pour accéder à la page. Il n'est pas nécessaire d'utiliser les deux sur chaque page, car si vous avez MandatoryPermissions, cela n'a pas d'importance si vous avez les options ou non.

Permission est un ENUM:


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

} 

Et MyUser est une implémentation de 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 
     // 
    } 
} 

la seule chose que vous devez faire dans vos pages est de remplir les listes d'autorisations:


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); 
    } 
} 

OK, l'exemple de recherche n'était pas très bon mais je pense que vous obtenez l'image.

L'idée générale est que base.OnLoad(e); est appelée juste avant la vérification des autorisations, il vous suffit donc de remplir les permissions dans votre Page_Load.

Je ne suis pas sûr que ce soit la meilleure solution, mais je suis sûr que ça aide beaucoup :)

+0

J'ai implémenté un MembershipProvider et un RoleProvider. Mes questions sont comment vous découpler l'autorisation des pages individuelles. Je veux dire, mettez-vous un Roles.IsInRole ("admin") dans chacune de vos pages? Utilisez-vous les éléments d'emplacement web.config? Ou avez-vous une autre façon de le découpler des pages? – JohannesH

+0

Ah, ok, donc je vais éditer ma réponse pour montrer comment je fais habituellement :) Juste une seconde – homemdelata

+0

Oui, l'approche de type "page de base" est ce que nous faisons aussi - Avoir une page de base qui gère toutes les authentification/accès contrôle, etc, et quelques autres fonctions, puis héritent des pages individuelles de cela. –

0

Avez-vous configuré les objets GenericIdentity et IPrincipal pendant votre méthode Application_AuthenticateRequest de l'application?

Nous utilisons actuellement notre domaine pour effectuer l'authentification et les groupes d'utilisateurs/rôles sur la base de données SQL Server pour fournir une autorisation. Au cours de la méthode Application_AuthenticateRequest, je rassemble toutes ces données et crée un objet FormsAuthenticationTicket basé sur celui-ci. Ce faisant, j'ai maintenant accès aux rôles de l'utilisateur en exécutant une simple commande User.IsInRole ("RoleX") dans mon code, ce qui me permet de verrouiller/déverrouiller facilement les commandes utilisateur, ou même de faire une simple réponse. .Redirect() à une page "Erreur d'autorisation" s'ils n'ont pas l'autorisation appropriée.

Voici ce que ma méthode de AuthenticateRequest ressemble (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 

... et même, voici ce que l'objet CustomPrincipal ressemble:

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 

Espérons que cela vous donne ce que vous besoin de le mouler dans votre environnement.

+0

Nous avons la même chose dans nos applications, car nous utilisons simplement un fournisseur de rôle personnalisé et un fournisseur d'appartenances pour l'authentification et le chargement des rôles. Qu'est-ce que je veux vraiment savoir, est-ce que vous avez ensuite coder en dur un User.IsInRole ("Admin") comme la première chose dans page_init sur chacune de vos pages d'administration. Ou avez-vous un autre moyen de découpler cette configuration? Je ne voudrais pas coder en dur les noms des rôles ou des règles Azman dans nos pages. – JohannesH

+0

J'utilise une combinaison d'autorisations web.config et de modèles maîtres pour réduire au minimum la vérification de mon code. J'ai aussi quelques fonctions auxiliaires comme "IsAdminAuthorized" et "IsManagerAuthorized" qui effectuent les contrôles composites lorsque les utilisateurs dans plusieurs rôles différents se qualifient comme un administrateur ou un gestionnaire. –

+0

Ok, pour moi ça me semble un peu trop couplé. Je n'aime pas coder dur. Fondamentalement, je pense que je dois faire quelque chose comme le module UrlAuthorization. – JohannesH

1

Que diriez-vous de mappage de pages à des rôles dans votre base de données, puis laissez votre masterpage vérifier la DB sur pageload?