When building a Web Part application, you might want to allow different users of the application to see different sets of Web Parts. For example, you might want the president of the company to be able to view the World Domination Plans Web Part, but you wouldn't want a lowly temporary employee to see the contents of this particular Web Part. On the other hand, you might want everyone in the company to be able to see the Copying Machine Locations Web Part. You can filter the Web Parts that a user can see on a Web Part page. When you create an authorization filter, only the Web Parts that a person is authorized to view will appear in Web Part Zones and Web Part Catalogs. You can create an authorization filter in either of two ways. First, you can handle the AuthorizeWebPart event of the WebPartManager control class. This event is raised every time that a Web Part is added to the page while the Web Part Framework builds the page. The event argument passed to the event handler for the AuthorizeWebPart event includes an IsAuthorized property. You can set this property to the value TRue or False to indicate whether a Web Part is authorized to be displayed. You can also create an authorization filter by creating a custom WebPartManager control that inherits from the WebPartManager control and overrides its IsAuthorized() method. The IsAuthorized() method returns a Boolean value. If you return the value False, then a Web Part fails authorization and it is not added to the page. Using this second way of creating an authorization filter makes sense when you want to apply the same authorization logic to multiple Web Part pages in an application. Regardless of whether you handle the AuthorizeWebPart event or you override the IsAuthorized() method, it is up to you to write the logic for the authorization filter. In the following sections, you'll learn three ways of filtering Web Parts, depending on the role of the user. Filtering by Authorization Filter One of the core properties shared by every Web Part is the AuthorizationFilter property. This property represents a string that you can use when filtering Web Parts. You can assign any string value to this property. For example, you can use the AuthorizationFilter property to represent a user role. In that case, in your AuthorizeWebPart event handler, you can prevent users who are not in the correct role from seeing a Web Part. In this section, we create three Web Parts: the MissionStatementPart, the CopyingMachinesLocationPart, and the WorldDominationPlanPart. These Web Parts are contained in Listings 28.12, 13, and 14. Listing 28.12. MissionStatementPart.ascx <%@ Control Language="VB" ClassName="MissionStatementPart" %> <h3>Mission Statement</h3> The purpose of this company is... | Listing 28.13. CopyingMachinesLocationPart.ascx <%@ Control Language="VB" ClassName="CopyingMachinesLocationPart" %> <h3>Copying Machines Location</h3> The copying machines are located on the 5th floor... | Listing 28.14. WorldDominationPlansPart.ascx <%@ Control Language="VB" ClassName="WorldDominationPlansPart" %> <h3>World Domination Plans</h3> Start by placing secret messages in every Unleashed book... | Notice that there is nothing special about these Web Parts. They are simply User controls. Next, because the Web Parts are filtered by user role, roles need to be enabled for the application. One option would be to use Windows Authentication and local Windows groups. This is the default type of authentication enabled for an ASP.NET application and there is nothing wrong with this option. However, this sample uses Forms Authentication and custom roles. It is easier to switch between users when using Forms Authentication, which makes it easier to test the page. Forms Authentication and custom roles can be enabled with the Web configuration file in Listing 28.15. Listing 28.15. Web.Config <?xml version="1.0"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.web> <authentication mode="Forms" /> <roleManager enabled="true" /> <membership defaultProvider="MyMembershipProvider"> <providers> <add name="MyMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="LocalSqlServer" requiresQuestionAndAnswer="false" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="1" requiresUniqueEmail="false" /> </providers> </membership> </system.web> </configuration> | CD Note The configuration file in Listing 28.15 is included on the CD with the name Web.Config_Disabled so that the configuration file doesn't interfere with the other samples in this chapter. The web configuration file in Listing 28.15 enables Forms Authentication and the Role Manager. It also configures the Membership provider so that email addresses and strong passwords are not required when creating a new user. (This makes it easier to create new users in the page.) Finally, the page in Listing 28.16 uses an authorization filter to display the three Web Parts (see Figure 28.6). Figure 28.6. Filtering Web Parts. Listing 28.16. ShowAuthorizationFilter.aspx [View full width] <%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="MissionStatementPart" src="/books/3/444/1/html/2/~/MissionStatementPart.ascx" %> <%@ Register TagPrefix="user" TagName="WorldDominationPlansPart" src="/books/3/444/1/html/2/~/WorldDominationPlansPart.ascx" %> <%@ Register TagPrefix="user" TagName="CopyingMachineLocationsPart" src="/books/3/444/1/html/2/~/CopyingMachinesLocationPart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> ''' <summary> ''' Create the Administrator and Serf roles and ''' create two users named Bill and Tom. ''' </summary> Private Sub Page_Load() If Not Roles.RoleExists("Administrator") Then Roles.CreateRole("Administrator") Roles.CreateRole("Serf") Membership.CreateUser("Bill", "secret") Membership.CreateUser("Tom", "secret") Roles.AddUserToRoles("Bill", New String(){"Administrator", "Serf"}) Roles.AddUserToRole("Tom", "Serf") End If End Sub ''' <summary> ''' Only add a Web Part when the AuthorizationFilter ''' property contains the current user's role or the ''' AuthorizationFilter property is empty. ''' </summary> Protected Sub WebPartManager1_AuthorizeWebPart(ByVal sender As Object, ByVal e As WebPartAuthorizationEventArgs) e.IsAuthorized = User.IsInRole(e.AuthorizationFilter) Or e.AuthorizationFilter = String.Empty End Sub ''' <summary> ''' Hide the menu for unauthorized users ''' </summary> Private Sub Page_PreRender() Menu1.Visible = Request.IsAuthenticated End Sub Protected Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <style type="text/css"> .login { border:solid 1px black; background-color:white; } .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Show Authorization Filter</title> </head> <body> <form runat="server"> <asp:WebPartManager OnAuthorizeWebPart="WebPartManager1_AuthorizeWebPart" Runat="server" /> <asp:Login Css TitleText="" Orientation="horizontal" DisplayRememberMe="false" Runat="server" /> <asp:Menu OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" Css Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Catalog" /> </Items> </asp:Menu> <asp:WebPartZone Css Runat="server"> <ZoneTemplate> <user:MissionStatementPart title="Mission Statement" runat="server" /> <user:CopyingMachineLocationsPart title="Copying Machine Locations" AuthorizationFilter="Serf" runat="server" /> <user:WorldDominationPlansPart title="World Domination Plans" AuthorizationFilter="Administrator" runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone Css Runat="server" /> <asp:CatalogZone Css Runat="server"> <ZoneTemplate> <asp:DeclarativeCatalogPart Runat="server"> <WebPartsTemplate> <user:CopyingMachineLocationsPart title="Copying Machine Locations" AuthorizationFilter="Serf" runat="server" /> <user:WorldDominationPlansPart title="World Domination Plans" AuthorizationFilter="Administrator" runat="server" /> </WebPartsTemplate> </asp:DeclarativeCatalogPart> <asp:PageCatalogPart Runat="server" /> </ZoneTemplate> </asp:CatalogZone> </form> </body> </html> | The Page_Load() method in Listing 28.16 automatically creates two roles named Administrator and Serf. The method also creates two users named Bill and Tom. Bill is associated with both the Administrator and Serf role and Tom is associated with the Serf role. After you open the page in Listing 28.16, you'll see only the MissionStatementPart Web Part because this is the only Web Part that anonymous users can view. If you log in with the username Tom and password secret, then you can see both the MissionStatementPart and CopyingMachineLocationsPart Web Parts. Both these Web Parts are visible in both the Web Part Zone and Catalog Zone contained in the page. Finally, if you log in with the username Bill and the password secret, you can see all three Web Parts. All three Web Parts are displayed in both the Web Part Zone and the Catalog Zone. Notice that the CopyingMachinesLocationPart and WorldDominationPlansPart Web Parts are declared with an AuthorizationFilter attribute. The CopyingMachinesLocationPart is associated with the Serf user role. The WorldDominiationPlansPart is associated with the Administrator user role. The WebPartManager control has an AuthorizeWebPart event handler associated with it. The event handler consists of the following line of code: e.IsAuthorized = User.IsInRole(e.AuthorizationFilter) Or e.AuthorizationFilter = String.Empty This line of code checks whether the current user is a member of the role represented by a Web Part's AuthorizationFilter property. If the user is in the role associated with the Web Part or the Web Part has no role associated with it, then the user is authorized to see the Web Part. Filtering by User Control Path Using the AuthorizationFilter property is potentially dangerous when you use the property with Generic Web Parts. The problem is that you might forget to add the AuthorizationFilter attribute when adding a Generic Web Part to a zone. Because the AuthorizationFilter property is not a member of the IWebPart interface, you cannot set this property in the User Control itself. This section explores an alternate method of creating an authorization filter. This method works only with Web Parts created as User Controls. Web Parts will be filtered depending on their paths. The idea is that to place every Web Part that a member of the Administrator role can see in a folder named Administrator. Furthermore, every Web Part that a member of the Serf role can see will be located in a folder named Serf. Let's start by creating the two User Controls contained in Listing 28.17 and 18. Listing 28.17. Serf\SerfPart.ascx <%@ Control Language="VB" ClassName="SerfPart" %> <h3>Serf Part</h3> | Listing 28.18. Administrator\AdministratorPart.ascx <%@ Control Language="VB" ClassName="AdministratorPart" %> <h3>Administrator Part</h3> | The SerfPart Web Part is located in the Serf folder and the AdministratorPart Web Part is located in the Administrator folder. The page in Listing 28.19 filters the two Web Parts. Different Web Parts are displayed, depending on the role of the current user. Listing 28.19. ShowAuthorizationPath.aspx [View full width] <%@ Page Language="VB" %> <%@ Register TagPrefix="user" TagName="AdministratorPart" src="/books/3/444/1/html/2/~/Administrator/AdministratorPart.ascx" %> <%@ Register TagPrefix="user" TagName="SerfPart" src="/books/3/444/1/html/2/~/Serf/SerfPart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> ''' <summary> ''' Create the Administrator and Serf roles and ''' the Bill and Tom user accounts ''' </summary> Private Sub Page_Load() If Not Roles.RoleExists("Administrator") Then Roles.CreateRole("Administrator") Roles.CreateRole("Serf") Membership.CreateUser("Bill", "secret") Membership.CreateUser("Tom", "secret") Roles.AddUserToRoles("Bill", New String(){"Administrator", "Serf"}) Roles.AddUserToRole("Tom", "Serf") End If End Sub ''' <summary> ''' Filter based on the Web Part User Control path ''' </summary> Protected Sub WebPartManager1_AuthorizeWebPart(ByVal sender As Object, ByVal e As WebPartAuthorizationEventArgs) e.IsAuthorized = User.IsInRole(GetFolder(e.Path)) End Sub ''' <summary> ''' Gets the name of the folder that contains ''' the User Control ''' </summary> Private Function GetFolder(ByVal path As String) As String Dim baseFolder As String = String.Empty Dim parts As String() = path.Split("/"c) If parts.Length > 2 Then baseFolder = parts(1) End If Return baseFolder End Function Private Sub Page_PreRender() Menu1.Visible = Request.IsAuthenticated End Sub Protected Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <style type="text/css"> .login { border:solid 1px black; background-color:white; } .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Show Authorization Path</title> </head> <body> <form runat="server"> <asp:WebPartManager OnAuthorizeWebPart="WebPartManager1_AuthorizeWebPart" Runat="server" /> <asp:Login Css TitleText="" Orientation="horizontal" DisplayRememberMe="false" Runat="server" /> <asp:Menu OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" Css Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Catalog" /> </Items> </asp:Menu> <asp:WebPartZone Css Runat="server"> <ZoneTemplate> <user:AdministratorPart title="Administrator Part" runat="server" /> <user:SerfPart title="Serf Part" runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone Css Runat="server" /> <asp:CatalogZone Css Runat="server"> <ZoneTemplate> <asp:DeclarativeCatalogPart Runat="server"> <WebPartsTemplate> <user:AdministratorPart title="Administrator Part" runat="server" /> <user:SerfPart title="Serf Part" runat="server" /> </WebPartsTemplate> </asp:DeclarativeCatalogPart> <asp:PageCatalogPart Runat="server" /> </ZoneTemplate> </asp:CatalogZone> </form> </body> </html> | After you open the page in Listing 28.19, you won't see any Web Parts. If you log in with the username Tom and password secret, you'll see the SerfPart Web Part. If you log in with the user name Bill and password secret, you'll see both the SerfPart and AdministratorPart Web Part (Bill is a member of both the Administrator and Serf roles). The AuthorizeWebPart event handler consists of the following single line of code: e.IsAuthorized = User.IsInRole( GetFolder(e.Path) ) The GetFolder() method returns the root folder of the Web Part being authorized. In other words, it returns the name of the folder where the User Control that corresponds to the Web Part is located. If the name of the root folder matches one of the current user's roles, then the Web Part is authorized and it is displayed in the page. Filtering by Custom Control Type You can't filter a True Web Part by its path because a True Web Part doesn't have a path. However, you can do something similar. Rather than filter a True Web Part by its path, you can filter a True Web Part by its type. In this section, two Web Part base classes are created, named AdministratorWebPartBase and SerfWebPartBase. Anyone who is a member of the Administrator role can see any Web Part that inherits directly from the AdministratorWebPartBase class, and anyone who is a member of the Serf role can see any Web Part that inherits directly from the SerfWebPartBase class. The AdministratorWebPartBase and SerfWebPartBase classes are contained in Listing 28.20 and Listing 28.21. Listing 28.20. App_Code\AdministratorWebPartBase.cs Imports System Imports System.Web.UI.WebControls.WebParts Namespace myControls ''' <summary> ''' Base class for all Web Parts that ''' an Administrator is authorized to see ''' </summary> Public MustInherit Class AdministratorWebPartBase Inherits WebPart End Class End Namespace | Listing 28.21. App_Code\SerfWebPartBase.cs Imports System Imports System.Web.UI.WebControls.WebParts Namespace myControls ''' <summary> ''' Base class for all Web Parts that ''' a member of the Serf role is authorized ''' to see. ''' </summary> Public MustInherit Class SerfWebPartBase Inherits WebPart End Class End Namespace | Now that we have the base classes, we can inherit any number of Administrator and Serf Web Parts from the base classes. Listing 28.22 and Listing 28.23 contain an Administrator Web Part and a Serf Web Part. Listing 28.22. App_Code\AdministratorPart.cs Imports System Imports System.Web.UI Imports System.Web.UI.WebControls.WebParts Namespace myControls ''' <summary> ''' A Web Part that only an Administrator can see ''' </summary> Public Class AdministratorPart Inherits AdministratorWebPartBase Private _title As String = "Administrator Part" Public Overrides Property Title() As String Get Return _title End Get Set(ByVal Value As String) _title = value End Set End Property Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter) writer.RenderBeginTag(HtmlTextWriterTag.H3) writer.Write("Administrator Part") writer.RenderEndTag() End Sub End Class End Namespace | Listing 28.23. App_Code\SerfPart.cs Imports System Imports System.Web.UI Imports System.Web.UI.WebControls.WebParts Namespace myControls ''' <summary> ''' A Web Part that only a Serf can see ''' </summary> Public Class SerfPart Inherits SerfWebPartBase Private _title As String = "Serf Part" Public Overrides Property Title() As String Get Return _title End Get Set(ByVal Value As String) _title = value End Set End Property Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter) writer.RenderBeginTag(HtmlTextWriterTag.H3) writer.Write("Serf Part") writer.RenderEndTag() End Sub End Class End Namespace | Notice that the AdministratorPart inherits from the AdministratorWebPartBase class, and the SerfPart inherits from the SerfWebPartBase class. The authorization filter in Listing 28.24 takes advantage of that fact. Listing 28.24. ShowAuthorizationType.aspx [View full width] <%@ Page Language="VB" %> <%@ Register TagPrefix="custom" Namespace="myControls" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> ''' <summary> ''' Create the Administrator and Serf roles and ''' the Bill and Tom user accounts. ''' </summary> Private Sub Page_Load() If Not Roles.RoleExists("Administrator") Then Roles.CreateRole("Administrator") Roles.CreateRole("Serf") Membership.CreateUser("Bill", "secret") Membership.CreateUser("Tom", "secret") Roles.AddUserToRoles("Bill", New String(){"Administrator", "Serf"}) Roles.AddUserToRole("Tom", "Serf") End If End Sub ''' <summary> ''' Authorizes a user to see a Web Part when the base type of the Web Part ''' matches one of the user's roles ''' </summary> Protected Sub WebPartManager1_AuthorizeWebPart(ByVal sender As Object, ByVal e As WebPartAuthorizationEventArgs) e.IsAuthorized = User.IsInRole(GetRoleFromType(e.Type)) End Sub ''' <summary> ''' Returns the name of the base class from a type ''' after stripping the text WebPartBase ''' </summary> Private Function GetRoleFromType(ByVal partType As Type) As String Dim typeName As String = partType.BaseType.Name Return typeName.Replace("WebPartBase", String.Empty) End Function Private Sub Page_PreRender() Menu1.Visible = Request.IsAuthenticated End Sub Protected Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <style type="text/css"> .login { border:solid 1px black; background-color:white; } .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Show Authorization Type</title> </head> <body> <form runat="server"> <asp:WebPartManager OnAuthorizeWebPart="WebPartManager1_AuthorizeWebPart" Runat="server" /> <asp:Login Css TitleText="" Orientation="horizontal" DisplayRememberMe="false" Runat="server" /> <asp:Menu OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" Css Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> <asp:MenuItem Text="Catalog" /> </Items> </asp:Menu> <asp:WebPartZone Css Runat="server"> <ZoneTemplate> <custom:AdministratorPart runat="Server" /> <custom:SerfPart runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone Css Runat="server" /> <asp:CatalogZone Css Runat="server"> <ZoneTemplate> <asp:DeclarativeCatalogPart Runat="server"> <WebPartsTemplate> <custom:AdministratorPart runat="Server" /> <custom:SerfPart runat="server" /> </WebPartsTemplate> </asp:DeclarativeCatalogPart> </ZoneTemplate> </asp:CatalogZone> </form> </body> </html> | Once again, Tom only can see the SerfPart Web Part, and Bill can see both the SerfPart and AdministratorPart Web Parts. The AuthorizeWebPart event handler consists of the following single line of code: e.IsAuthorized = User.IsInRole(GetRoleFromType(e.Type)) The GetroleFromType() method returns the name of the base type of the current Web Part (and strips the string "WebPartBase" from the name). If the current user is a member of the role represented by the base type, then the user can see the Web Part. |