1. The first step is to create an admin user to be recognized by your ASP.NET application. This user will have the privilege to access the catalog administration page. Start the ASP.NET Web Site Administration Tool by clicking WebSite ➤ ASP.NET Configuration.
2. Click the Security tab. You should get a screen like the one shown in Figure 8-7.
Darie-Watson_4681C08.fm Page 230 Monday, September 19, 2005 9:55 AM
8213592a117456a340854d18cee57603
C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N 231
Figure 8-7. The ASP.NET Web Site Administration Tool
3. Click Enable roles.
4. Click Create or Manage roles and create a new role named Administrators. Click Back.
5. The default authentication type is Windows. Click Select authentication type and select the From the Internet option. Click Done.
6. Click Create user and add a new user that will be allowed to perform catalog administration tasks. We’ll assume you add a new user named admin with the password BalloonShop!. Add some text of your choice for E-mail, Security Question, and Security Answer. Assign the user to the Administrators role by checking the check box, and click Create User (see Figure 8-8).
Darie-Watson_4681C08.fm Page 231 Monday, September 19, 2005 9:55 AM
232 C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N
Figure 8-8. Creating a new user
■ Note The default security settings require users to have strong passwords, so your password may be rejected if you try simpler passwords. This is because the ASP.NET membership system applies several rules to passwords, which are defined in machine.config. By default, passwords require a minimum length of seven characters, including at least one nonalphanumeric character (that is, a symbol character such as [, *,
!, and so on). These settings can be changed by editing the machine.config file, which is located in
<Windows Install Directory>\Microsoft.NET\Framework\<Version>\CONFIG\. Look for the definition of the AspNetSqlMembershipProvider provider, which can include the
minRequiredPasswordLength and minRequiredNonalphanumericCharacters attributes to define the length and complexity of the password (or you can do this in one go using the
passwordStrengthRegularExpression parameter). However, be aware that changes you make in machine.config apply to all the web sites on your computer. An alternative is to override the definition of this provider in web.config—you’ll learn more details about this in Chapter 12.
7. Click Back to get to the main Security page. Make sure that you have one role and one user and then close the window.
Darie-Watson_4681C08.fm Page 232 Monday, September 19, 2005 9:55 AM
C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N 233
8. Switch back to Visual Studio. You’ll probably be asked to reload web.config, which was modified by an external program. Select Yes.
9. Next you’ll create the UserInfo Web User Control, the Login Web Form, and the skeleton of the CatalogAdmin Web Form. First add the following styles to BalloonShop.css, which will be used in these pages:
.UserInfoHead {
border-right: #cc6666 1px solid;
border-top: #cc6666 1px solid;
border-left: #cc6666 1px solid;
border-bottom: #cc6666 1px solid;
background-color: #dc143c;
font-family: Verdana, Arial;
font-weight: bold;
font-size: 10pt;
color: #f5f5dc;
padding-left: 3px;
text-align: center;
}
.UserInfoContent {
border-right: #cc6666 1px solid;
border-top: #cc6666 1px solid;
border-left: #cc6666 1px solid;
border-bottom: #cc6666 1px solid;
background-color: #ffcccc;
text-align: center;
}
.UserInfoText {
font-family: Verdana, Arial;
font-size: 9pt;
padding-left: 5px;
text-decoration: none;
}
a.UserInfoLink {
font-family: Verdana, Arial;
font-weight: bold;
font-size: 9pt;
color: #ed486d;
line-height: 15px;
padding-left: 5px;
text-decoration: none;
}
Darie-Watson_4681C08.fm Page 233 Monday, September 19, 2005 9:55 AM
234 C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N
a.UserInfoLink:hover {
padding-left: 5px;
color: #dc143c;
} .Button {
color: Black;
font-family: Verdana, Helvetica, sans-serif;
font-size: 12px;
}
.AdminTitle {
color: Black;
font-family: Verdana, Helvetica, sans-serif;
text-decoration: none;
font-size: 21px;
font-weight: bold;
line-height: 25px;
}
.AdminPageText {
color: Navy;
font-family: Verdana, Helvetica, sans-serif;
text-decoration: none;
font-size: 12px;
}
a.AdminPageText {
color: Navy;
font-family: Verdana, Helvetica, sans-serif;
text-decoration: none;
font-size: 12px;
}
a.AdminPageText:hover {
color:Red;
}
10. Now, create a Web User Control named UserInfo.ascx in your UserControls folder.
11. In UserInfo, you’ll use a new ASP.NET 2.0 control named LoginView, which can display different data (through templates) depending on the currently logged-in user. For users of the Administrators role, you’ll display links to the administration pages, and if no users are logged in, you simply display a login link (using the LoginStatus control). You can edit the templates of the LoginView control by either using Design View or Source View. Either way, make sure your UserInfo Web User Control contains the following code:
Darie-Watson_4681C08.fm Page 234 Monday, September 19, 2005 9:55 AM
C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N 235
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="UserInfo.ascx.cs"
Inherits="UserInfo" %>
<table cellspacing="0" border="0" width="200px" class="UserInfoContent">
<tr>
<td class="UserInfoHead">
User Info</td>
</tr>
<asp:LoginView ID="LoginView1" runat="server">
<AnonymousTemplate>
<tr>
<td>
<span class="UserInfoText">You are not logged in.</span>
</td>
</tr>
<tr>
<td>
»
<asp:LoginStatus ID="LoginStatus1" runat="server"
CssClass="UserInfoLink" />
«
</td>
</tr>
</AnonymousTemplate>
<RoleGroups>
<asp:RoleGroup Roles="Administrators">
<ContentTemplate>
<tr>
<td>
<asp:LoginName ID="LoginName2" runat="server" FormatString=
"You are logged in as <b>{0}</b>. "
CssClass="UserInfoText" />
</td>
</tr>
<tr>
<td>
»
<asp:LoginStatus ID="LoginStatus2" runat="server" CssClass=
"UserInfoLink" />
«
</td>
</tr>
<tr>
<td>
»
<a class="UserInfoLink" href="CatalogAdmin.aspx">
Darie-Watson_4681C08.fm Page 235 Monday, September 19, 2005 9:55 AM
236 C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N
Catalog Admin</a>
«
</td>
</tr>
</ContentTemplate>
</asp:RoleGroup>
</RoleGroups>
</asp:LoginView>
</table>
12. Open BalloonShop.master and drag the UserInfo control from Solution Explorer just before the list of departments, as shown in Figure 8-9.
Figure 8-9. Adding the UserInfo control to the Master Page
13. Start your project and ensure that your UserInfo control looks good. The next step is to create the login page. Right-click the root entry in Solution Explorer, select Add New Item, choose the Web Form template, and name it Login.aspx. Make sure the two check boxes are checked and click Add.
14. In the dialog box that opens, select the BalloonShop.master entry and click OK.
Darie-Watson_4681C08.fm Page 236 Monday, September 19, 2005 9:55 AM
C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N 237
15. Switch Login.aspx to Design View, add a Login control from the Login tab of the toolbox to the content placeholder, and then rename the control from Login1 to login, as shown in Figure 8-10.
Figure 8-10. The content area of Login.aspx in Design View
16. Open web.config and change the <authentication> element under the <system.web> node, as shown next. This registers Login.aspx as the default login page, which visitors will be forwarded to if they click the Login link or when they try to access an unauthorized page.
<authentication mode="Forms">
<forms name="BalloonShopLogin"
loginUrl="Login.aspx" path="/" protection="All" timeout="60">
</forms>
</authentication>
At this point, you have a working login and logout mechanism! Start your project to ensure the login and logout features are fully working (try to log in with the username admin, which should have as the password BalloonShop!, if you followed the instructions).
■Note After you type your username and password, it’s not enough to just press the Enter key while the focus is on the Password text box or on the check box. You need to press the Tab key to give the Log In button the focus or click the Log In button with the mouse. You’ll fix this problem in the next steps by using the TieButton method that you implemented in Chapter 5 (I told you that method would be useful!).
17. Continue by doing a few cosmetic changes to your page. To make the Login control fully customizable by having access to its individual constituent controls, you need to convert it to a template. Click its Smart Link and choose Convert to Template, as shown in Figure 8-11.
Darie-Watson_4681C08.fm Page 237 Monday, September 19, 2005 9:55 AM
8213592a117456a340854d18cee57603
238 C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N
Figure 8-11. Converting the Login control to a template
18. Switch to Source View. After converting the control to a template, you’ll see all of its constituent controls gen- erated inside its <LayoutTemplate>. Modify the template as shown in the following code snippet:
<LayoutTemplate>
<table border="0" cellpadding="1">
<tr class="UserInfoText">
<td>
<table border="0" cellpadding="0">
<tr>
<td class="CatalogTitle" align="left" colspan="2">
Who Are You?<br /><br />
</td>
</tr>
<tr>
...
19. Remember the TieButton method you wrote in Chapter 5? You’ll use it here again to link the username and password text boxes to the Log In button. After converting the Login control to use templates, not only is it easy to change how the control looks, but you can also see the names of the constituent controls (more specifically, you want to find the names of the two TextBox controls and the name of the Button control). Open the code-behind file Login.aspx.cs and modify Page_Load like this:
protected void Page_Load(object sender, EventArgs e) {
// get references to the button, checkbox and textboxes
TextBox usernameTextBox = (TextBox)login.FindControl("UserName");
TextBox passwordTextBox = (TextBox)login.FindControl("Password");
CheckBox persistCheckBox = (CheckBox)login.FindControl("RememberMe");
Button loginButton = (Button)login.FindControl("LoginButton");
// tie the two textboxes and the checkbox to the button Utilities.TieButton(this.Page, usernameTextBox, loginButton);
Utilities.TieButton(this.Page, passwordTextBox, loginButton);
Utilities.TieButton(this.Page, persistCheckBox, loginButton);
Darie-Watson_4681C08.fm Page 238 Monday, September 19, 2005 9:55 AM
C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N 239
// set the page title
this.Title = BalloonShopConfiguration.SiteName + " : Login";
// set focus on the username textbox when the page loads usernameTextBox.Focus();
}
20. Now your login page not only that works well, but it also looks good and is very user-friendly. The next and final task for this exercise is to create the skeleton of your administrative part of the site. Start by creating a new Master Page to be used by all the admin pages you’ll build for BalloonShop. Right-click the project name in Solution Explorer, choose Add New Item, select Master Page, and type Admin.master for the name. Choose Visual C# for the language, make sure Place code in separate file is checked, and click Add.
21. While editing the page in Source View, modify the body like this:
<body>
<form id="form1" runat="server">
<table cellspacing="0" cellpadding="0" border="0" width="100%">
<tr = valign="top">
<td width="220">
<uc1:UserInfo ID="UserInfo1" runat="server" />
</td>
<td valign="top">
<span class="AdminTitle">
<% Response.Write(BalloonShopConfiguration.SiteName); %>
</span>
(<a href="Default.aspx" class="AdminPageText">go back to BalloonShop</a>)
<br />
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</td>
</tr>
</table>
<br />
<asp:ContentPlaceHolder ID="ContentPlaceHolder2" runat="server">
</asp:ContentPlaceHolder>
</form>
</body>
22. Switch to Design View and drag the UserInfo.ascx control you wrote earlier from the Solution Explorer, near the “Login here” text in your page. Delete the “Login here” text, and your page should look like Figure 8-12.
Darie-Watson_4681C08.fm Page 239 Monday, September 19, 2005 9:55 AM
240 C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N
Figure 8-12. Admin.master in Design View
23. Add a new Web Form called CatalogAdmin.aspx to the project. Make sure its language is Visual C#
and that both check boxes (Place code in separate file and Select master page) are checked. Click Add, choose the Admin.master Master Page, and then click OK.
24. In CatalogAdmin.aspx, write the following code in the first content area:
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1"
Runat="server">
<span class="AdminTitle">Catalog Admin</span>
</asp:Content>
25. Add a PlaceHolder object from the toolbox to the second content area and change its ID to adminPlaceHolder.
26. Double-click web.config in Solution Explorer and add the following sections to it. Be aware that the default authentication mode is Windows, and you’ll need to change it to Forms:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<appSettings>
...
</appSettings>
<connectionStrings>
...
Darie-Watson_4681C08.fm Page 240 Monday, September 19, 2005 9:55 AM
C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N 241
</connectionStrings>
<!-- Only administrators are allowed to access CatalogAdmin.aspx -->
<location path="CatalogAdmin.aspx">
<system.web>
<authorization>
<allow roles="Administrators" />
<deny users="*" />
</authorization>
</system.web>
</location>
<system.web>
...
How It Works: The Security Mechanism
Congratulations for finishing this long exercise! First, test that your new features work as expected. Try also to access the CatalogAdmin.aspx page without being logged in as Administrator or try to log out when you’re in the admin page. You should be forwarded to the login page.
In this exercise, you first added the Administrators role and the admin user to your site. You performed these tasks using the ASP.NET Web Application Administration page. Feel free to check out other options of that page as well.
For instance, you can access and manage the options you saved to web.config (such as SiteName, and so on) by going to the Application tab, and then clicking Create/Manage application settings.
The security data is saved in the App_Data folder of your application, in either an Access database or in an SQL Server Express database named ASPNETDB. After this database is created, you can access it from the Database Explorer window. You can change the engine used for this database from the ASP.NET Configuration page, on the Provider tab.
After adding the admin user, you created the UserInfo Web User Control. There you used a number of the new .NET 2.0 login controls that were explained previously. You could have used the designer to build these controls and their templates—and you can still use the designer to edit them, which I encourage you to test—but in this exercise, it was easier to simply type the code. Let’s see how these controls were used:
• LoginView is capable of displaying various templates depending on what user is logged in at the moment.
The AnonymousTemplate is displayed if no user is logged in, and it generates the “You are not logged in” text and a link to the login page.
<AnonymousTemplate>
<tr>
<td>
<span class="UserInfoText">You are not logged in.</span>
</td>
</tr>
<tr>
<td>
»
<asp:LoginStatus ID="LoginStatus1" runat="server"
Darie-Watson_4681C08.fm Page 241 Monday, September 19, 2005 9:55 AM
242 C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N
CssClass="UserInfoLink" />
</asp:HyperLink>
«
</td>
</tr>
</AnonymousTemplate>
• Then, under the RoleGroups template, you can find the HTML code that is displayed when an admin- istrator is logged in.
• LoginName simply displays the “You are logged in as username” text. This text is defined in its FormatString property, where {0} is the username.
<asp:LoginName ID="LoginName2" runat="server"
FormatString="You are logged in as <b>{0}</b>. " CssClass="UserInfoText" />
• LoginStatus displays a Login link that forwards you to the login page you configured in web.config, or a Logout button that logs out the currently logged-in user and clears the current session information.
<asp:LoginStatus ID="LoginStatus1" runat="server" CssClass="UserInfoLink" />
After writing the UserInfo control, you created Login.aspx. Creating this page was extremely simple, because its only role is to contain a Login control. That control does the login work by itself, without requiring you to write any line of code or configure any settings. The extra steps you took for creating Login.aspx were for customizing the look of the Login control and converting it into a template to have access to its inner controls. Knowing the names of the inner controls helped you use the Utilities.TieButton method to tie the two text boxes and the one check box to the Log In button. This way, if the visitor presses Enter while any of the text boxes or the check box has focus, the Log In button is automatically clicked (otherwise, the page would have been refreshed without per- forming any login functionality).
Finally, CatalogAdmin.aspx was created to serve as a skeleton for the future catalog admin page. You configured it through web.config to be only accessible by users of the Administrators role:
<!-- Only administrators are allowed to access CatalogAdmin.aspx -->
<location path="CatalogAdmin.aspx">
<system.web>
<authorization>
<allow roles="Administrators" />
<deny users="*" />
</authorization>
</system.web>
</location>
Note that the authorization list is interpreted in sequential order. The following combination would reject all login attempts:
<deny users="*" />
<allow roles="Administrators" />
The * wildcard is used for “all identities.” The other wildcard character, ?, means “anonymous users.” If you wanted all anonymous users to be denied, you could have used the following:
Darie-Watson_4681C08.fm Page 242 Monday, September 19, 2005 9:55 AM
C H A P T E R 8 ■ C A T A L O G A D M I N I S T R A T I O N 243
<location path="CatalogAdmin.aspx">
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
With this setting, any logged-in users (not only administrators) would be allowed access to the admin page.
■Tip By default, all visitors are allowed access to all pages, so you need to explicitly deny access to the sensitive pages.