ASP.NET页面授权......你是怎么做到的?

时间:2021-04-05 20:54:38

I'm currently investigating alternative solutions to the standard page authorization configuration in asp.net.

我正在研究asp.net中标准页面授权配置的替代解决方案。

The location tag works ok if you have directories of files that need the same access policy but if you have lots of individual access policies the location tag is a pain. I could roll my own custom auth system but if it can be avoided thats probably better.

如果您的文件目录需要相同的访问策略,但是如果您有许多单独的访问策略,则位置标记很难处理。我可以滚动我自己的自定义身份验证系统,但如果可以避免那可能更好。

Currently we're using a azman-like permission based authorization system for page content but I haven't found a good way of integrating this with the standard page security yet.

目前我们正在为页面内容使用类似azman的权限授权系统,但我还没有找到将其与标准页面安全性集成的好方法。

Any suggestions on how to do this? Are there any solutions integrating azman and asp.net page authorization? Are there any other standard solutions I should be aware of?

有关如何做到这一点的任何建议?有没有集成azman和asp.net页面授权的解决方案?我应该注意哪些其他标准解决方案?

3 个解决方案

#1


I did in a huge application having lots of different permissions and different roles something like the following [I don't have the code here so I'll just try to recreate it here]:

我在一个巨大的应用程序中做了很多不同的权限和不同的角色,如下所示[我没有这里的代码所以我只是尝试在这里重新创建]:

I first implemented a class called SecuredPage as following:

我首先实现了一个名为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();
    }
}

This will be my BasePage for all pages that user need permissions to access. The MandatoryPermissions are permissions that user MUST have all of them to access the page and OptionalPermissions are permissions that user needs at least one of them to access the page. There's no need to use both on every page because if you have MandatoryPermissions doesn't matter if you have the optionals or not.

对于用户需要访问权限的所有页面,这将是我的BasePage。 MandatoryPermissions是用户必须拥有访问页面的权限,而OptionalPermissions是用户至少需要其中一个访问页面的权限。没有必要在每个页面上同时使用这两个页面,因为如果你有MandatoryPermissions,那么无论你是否有选项都无关紧要。

Permission is a enum:

许可是一个枚举:


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

}

And MyUser is a implementation of MembershipUser:

而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
        //
    }
}

Then the only thing that you need to do in your pages is to populate the permissions lists:

然后,您在页面中唯一需要做的就是填充权限列表:


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, the search example wasn't that good but I think you get the picture.

好的,搜索示例不是那么好,但我认为你得到了图片。

The whole idea is that base.OnLoad(e); is called just before the permissions verification, so you just need to fill the permissions in your Page_Load.

整个想法是base.OnLoad(e);在权限验证之前调用,因此您只需要填写Page_Load中的权限。

I'm not sure if this is the best solution but I'm sure it helps a lot :)

我不确定这是否是最佳解决方案,但我确信它有很大帮助:)

#2


How about mapping pages to roles in your database and then let your masterpage check the DB on pageload?

如何将页面映射到数据库中的角色,然后让您的母版页检查页面上的数据库?

#3


Have you setup the GenericIdentity and IPrincipal objects during your Application_AuthenticateRequest method of the application?

您是否在应用程序的Application_AuthenticateRequest方法中设置了GenericIdentity和IPrincipal对象?

We currently use our domain to do authentication and user groups/roles on the SQL Server database to provide authorization. During the Application_AuthenticateRequest method, I gather all this data and create a FormsAuthenticationTicket object based on it.

我们目前使用我们的域在SQL Server数据库上执行身份验证和用户组/角色以提供授权。在Application_AuthenticateRequest方法期间,我收集所有这些数据并基于它创建FormsAuthenticationTicket对象。

By doing so, I now have access to the user's roles by performing a simple User.IsInRole("RoleX") command in my code, which allows me to easily lock/unlock user controls, or even do a simple Response.Redirect() to a "Authorization Error" page if they don't have the proper authorization.

通过这样做,我现在可以通过在我的代码中执行简单的User.IsInRole(“RoleX”)命令来访问用户的角色,这使我可以轻松锁定/解锁用户控件,甚至可以执行简单的Response.Redirect()如果他们没有适当的授权,请到“授权错误”页面。

Here's what my AuthenticateRequest method looks like (VB.NET)

这是我的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

...and similarly, here's what the CustomPrincipal object looks like:

...同样,这是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

Hopefully this gives you what you need to mold it into your environment.

希望这能为您提供将其塑造成环境所需的一切。

#1


I did in a huge application having lots of different permissions and different roles something like the following [I don't have the code here so I'll just try to recreate it here]:

我在一个巨大的应用程序中做了很多不同的权限和不同的角色,如下所示[我没有这里的代码所以我只是尝试在这里重新创建]:

I first implemented a class called SecuredPage as following:

我首先实现了一个名为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();
    }
}

This will be my BasePage for all pages that user need permissions to access. The MandatoryPermissions are permissions that user MUST have all of them to access the page and OptionalPermissions are permissions that user needs at least one of them to access the page. There's no need to use both on every page because if you have MandatoryPermissions doesn't matter if you have the optionals or not.

对于用户需要访问权限的所有页面,这将是我的BasePage。 MandatoryPermissions是用户必须拥有访问页面的权限,而OptionalPermissions是用户至少需要其中一个访问页面的权限。没有必要在每个页面上同时使用这两个页面,因为如果你有MandatoryPermissions,那么无论你是否有选项都无关紧要。

Permission is a enum:

许可是一个枚举:


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

}

And MyUser is a implementation of MembershipUser:

而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
        //
    }
}

Then the only thing that you need to do in your pages is to populate the permissions lists:

然后,您在页面中唯一需要做的就是填充权限列表:


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, the search example wasn't that good but I think you get the picture.

好的,搜索示例不是那么好,但我认为你得到了图片。

The whole idea is that base.OnLoad(e); is called just before the permissions verification, so you just need to fill the permissions in your Page_Load.

整个想法是base.OnLoad(e);在权限验证之前调用,因此您只需要填写Page_Load中的权限。

I'm not sure if this is the best solution but I'm sure it helps a lot :)

我不确定这是否是最佳解决方案,但我确信它有很大帮助:)

#2


How about mapping pages to roles in your database and then let your masterpage check the DB on pageload?

如何将页面映射到数据库中的角色,然后让您的母版页检查页面上的数据库?

#3


Have you setup the GenericIdentity and IPrincipal objects during your Application_AuthenticateRequest method of the application?

您是否在应用程序的Application_AuthenticateRequest方法中设置了GenericIdentity和IPrincipal对象?

We currently use our domain to do authentication and user groups/roles on the SQL Server database to provide authorization. During the Application_AuthenticateRequest method, I gather all this data and create a FormsAuthenticationTicket object based on it.

我们目前使用我们的域在SQL Server数据库上执行身份验证和用户组/角色以提供授权。在Application_AuthenticateRequest方法期间,我收集所有这些数据并基于它创建FormsAuthenticationTicket对象。

By doing so, I now have access to the user's roles by performing a simple User.IsInRole("RoleX") command in my code, which allows me to easily lock/unlock user controls, or even do a simple Response.Redirect() to a "Authorization Error" page if they don't have the proper authorization.

通过这样做,我现在可以通过在我的代码中执行简单的User.IsInRole(“RoleX”)命令来访问用户的角色,这使我可以轻松锁定/解锁用户控件,甚至可以执行简单的Response.Redirect()如果他们没有适当的授权,请到“授权错误”页面。

Here's what my AuthenticateRequest method looks like (VB.NET)

这是我的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

...and similarly, here's what the CustomPrincipal object looks like:

...同样,这是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

Hopefully this gives you what you need to mold it into your environment.

希望这能为您提供将其塑造成环境所需的一切。