这是我之前的问题的延续。
我曾尝试使用内置的 ASP 登录机制,但它对我不起作用。主要原因是,我被要求保持简洁。
现在,这就是我的立场:
网页配置
<system.web>
<sessionState timeout="10" />
<authentication mode="Forms">
<forms timeout="30" loginUrl="~/SecuredArea/LogInOut/log-in.aspx" />
</authentication>
<authorization>
<allow users="?" />
</authorization>
</system.web>
<location path="SecuredArea/AdminArea">
<system.web>
<authorization>
<allow roles="administrators" />
<deny users="*" />
</authorization>
</system.web>
</location>
<location path="SecuredArea/EmployeeArea">
<system.web>
<authorization>
<allow roles="employees" />
<deny users="*" />
</authorization>
</system.web>
</location>
全球.asax
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
IIdentity userId = HttpContext.Current.User.Identity;
//if role info is already NOT loaded into cache, put the role info in cache
//if (HttpContext.Current.Cache[userId.Name] == null)
//{
// string[] roles;
// if (userId.Name == "admin")
// {
// roles = new string[1] { "administrators" };
// }
// else if (userId.Name == "member1")
// {
// roles = new string[1] { "employees" };
// }
// else
// {
// roles = new string[1] { "public" };
// }
//1 hour sliding expiring time. Adding the roles in cache.
//This will be used in Application_AuthenticateRequest event located in Global.ascx.cs
//file to attach user Principal object.
// HttpContext.Current.Cache.Add(userId.Name, roles, null, DateTime.MaxValue, TimeSpan.FromHours(1), CacheItemPriority.BelowNormal, null);
//}
//now assign the user role in the current security context
HttpContext.Current.User = new GenericPrincipal(userId, (string[])HttpContext.Current.Cache[userId.Name]);
}
}
}
我在这里评论了令人困惑的代码,因为我不想在这里访问数据库并遍历所有可能的员工。对于管理员帐户,这很容易,但对于员工帐户,这是不可能的。
登录.aspx.cs
protected void ButtonLogOn_Click(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(txtUserName.Value.Trim()) || String.IsNullOrEmpty(txtPassword.Value.Trim()))
{
labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("You can login using a username and a password associated with your account. Make sure that it is typed correctly.");
}
else
{
try
{
LoginPage loginBack = new LoginPage();
int result = loginBack.VerifyCredentials(txtUserName.Value.Trim(), txtPassword.Value.Trim());
switch (result)
{
case -9:
//System needs provisioning
labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("SMB Password Reset System need provisioning. Login as Administrator.");
break;
case 0:
//Enroll-able User
// Success, create non-persistent authentication cookie.
FormsAuthentication.SetAuthCookie(txtUserName.Value.Trim(), false);
FormsAuthenticationTicket ticketEmployee =
new FormsAuthenticationTicket(
1, // version
txtUserName.Value.Trim(), // get username from the form
DateTime.Now, // issue time is now
DateTime.Now.AddMinutes(10), // expires in 10 minutes
false, // cookie is not persistent
"employees");
HttpCookie cookieEmployee = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticketEmployee));
Response.Cookies.Add(cookieEmployee);
SiteLogin.PerformAuthentication(txtUserName.Value.Trim(), false);
break;
case 1:
//User not in required directory group
labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("You cannot login because you are not authorized.");
break;
default:
//Bad name and/or password
labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("You can login using a username and a password associated with your account. Make sure that it is typed correctly.");
break;
}
}
catch (MessageSecurityException expMse)
{
//Bad name and/or password
Debug.WriteLine("Error: " + expMse.Message);
labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("You can login using a username and a password associated with your account. Make sure that it is typed correctly.");
}
catch (Exception exp)
{
labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("Some general error has occured. Message reads: " + exp.Message);
}
}
}
protected void ButtonAdminLogOn_Click(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(txtUserName.Value) || String.IsNullOrEmpty(txtPassword.Value))
labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("<strong>Login Please!</strong><hr/>You can login using a username and a password associated with your account. Make sure that it is typed correctly.");
else
{
//if the log-in is successful
if (txtUserName.Value == "admin" && txtPassword.Value == "AlphaBeta")
{
// Success, create non-persistent authentication cookie.
FormsAuthentication.SetAuthCookie(txtUserName.Value.Trim(), false);
FormsAuthenticationTicket ticketAdmin =
new FormsAuthenticationTicket(
1, // version
txtUserName.Value.Trim(), // get username from the form
DateTime.Now, // issue time is now
DateTime.Now.AddMinutes(10), // expires in 10 minutes
false, // cookie is not persistent
"administrators");
HttpCookie cookieAdmin = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticketAdmin));
Response.Cookies.Add(cookieAdmin);
SiteLogin.PerformAdminAuthentication(txtUserName.Value.Trim(), false);
}
else
{
labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("<strong>Login Failed!</strong><hr/>The username and/or password you entered do not belong to any Administrator account on our system.<br/>You can login using a username and a password associated with your account. Make sure that it is typed correctly.");
}
}
}
最后,实用程序类:SiteLogin.cs
public sealed class SiteLogin
{
public static void PerformAuthentication(string userName, bool remember)
{
FormsAuthentication.RedirectFromLoginPage(userName, remember);
if (HttpContext.Current.Request.QueryString["ReturnUrl"] == null)
{
RedirectToDefaultPage();
}
else
{
HttpContext.Current.Response.Redirect(HttpContext.Current.Request.QueryString["ReturnUrl"]);
}
}
public static void PerformAdminAuthentication(string userName, bool remember)
{
FormsAuthentication.RedirectFromLoginPage(userName, remember);
if (HttpContext.Current.Request.QueryString["ReturnUrl"] == null)
{
RedirectToAdminDefaultPage();
}
else
{
HttpContext.Current.Response.Redirect(HttpContext.Current.Request.QueryString["ReturnUrl"]);
}
}
/// <summary>
/// Redirects the current user based on role
/// </summary>
public static void RedirectToDefaultPage()
{
HttpContext.Current.Response.Redirect("~/SecuredArea/EmployeeArea/EmployeeDefaultPage.aspx");
}
/// <summary>
/// Redirects the current user based on role
/// </summary>
public static void RedirectToAdminDefaultPage()
{
HttpContext.Current.Response.Redirect("~/SecuredArea/AdminArea/AdminDefaultPage.aspx");
}
public static void LogOff()
{
// Put user code to initialize the page here
FormsAuthentication.SignOut();
//// Invalidate roles token
//Response.Cookies[Globals.UserRoles].Value = "";
//Response.Cookies[Globals.UserRoles].Path = "/";
//Response.Cookies[Globals.UserRoles].Expires = new System.DateTime(1999, 10, 12);
//Set the current user as null
HttpContext.Current.User = null;
}
}
现在,每当我尝试登录时,我都会遇到严重不一致的行为。最大的问题是,一旦我尝试访问管理员或员工的任何受保护页面,我就会被重定向到登录页面。我提供了详细信息并尝试登录,在两种情况下(简单的管理员登录和复杂的员工登录),我都在浏览器中收到错误。IE 没有多大意义,但 Firefox 抱怨是有道理的:
页面未正确重定向 Pale Moon 检测到服务器正在以永远不会完成的方式重定向对该地址的请求。 此问题有时可能是由禁用或拒绝接受 cookie 引起的。
我在调试它时遇到了麻烦,但似乎是 insideGlobal.asax
的Application_AuthenticateRequest()
方法,该方法只是一遍又一遍地调用。
有趣的是,如果我转到未受保护的页面,我可以看到自己已登录并在我的标题中看到“欢迎管理员!,注销”。这是通过母版页动态完成的
<div class="info-area">
<asp:LoginView ID="HeadLoginView" runat="server" EnableViewState="false">
<LoggedInTemplate>
Welcome <span class="bold">
<asp:LoginName ID="HeadLoginName" runat="server" />
</span>! |
</LoggedInTemplate>
</asp:LoginView>
<asp:LoginStatus ID="HeadLoginStatus" runat="server" LogoutAction="Redirect" LogoutText="Logout" LogoutPageUrl="~/SecuredArea/LogInOut/log-out.aspx" />
</div>
任何人都可以确定问题吗?我今天真的需要关闭这个东西。谢谢。
编辑
我用过提琴手,我看到一旦我按下登录,就会创建一个无限循环。我可以通过图像显示行为:
访问安全区域时被抛出到登录页面
输入凭据并按下登录按钮
凭据被接受并重定向回安全页面并再次重定向到登录等等
我选择了 fiddler 的 Cookies 选项卡,因为那里检测到了明显的变化。