asp.net 使用母版页自定义用户身份验证
asp.net custom user authentication with master page
我正在开发一个小型库存管理系统。我几乎已经在我的本地机器上创建了它。它按设计工作。我刚把它移到我的主机帐户,现在我遇到了一些问题。
1、登录后,当用户转到不同的页面时,打开和关闭表单,一段时间后重定向到登录页面。我不知道为什么。似乎发生了某种异常或会话为空。如何处理这种情况?
2,这是使用母版页的 Page_Load 事件检查用户登录的正确方法吗?
我的网站使用母版页,顶部导航菜单和底部正文区域具有单独的布局。当用户第一次登陆网站时,它会登录系统,成功登录后,我会将他的信息存储在会话中。为了添加、删除、更新目的,我在所有页面中大量使用 Session。执行添加记录时,我在会话中传递成功或失败消息以在 post 后显示。登录页面隐藏代码如下:
protected void loginForm_OnAuthenticate(object sender, AuthenticateEventArgs e)
{
string error = "";
sMethodName = "loginForm_OnAuthenticate";
_objLoginBLL = new LoginBLL();
int iRetVal = _objLoginBLL.ValidateUser(loginForm.UserName, loginForm.Password, ref error);
if (iRetVal >= 0)
{
Session.Clear(); //Remove all stored Session variables.
Session[Constant.Session.LOGGED_IN_DATETIME] = DateTime.Now.ToString("yyyyMMddHHmmssfff");
Session[Constant.Session.LOGIN_USERNAME] = loginForm.UserName;
Session[Constant.Session.LOGIN_USER_ID] = iRetVal;
Session[Constant.Session.LOGIN_COMPANY] = ddlCompanies.SelectedValue;
Session[Constant.Session.LOGIN_FISCAL_YEAR] = ddlFiscalYear.SelectedValue;
Session[Constant.Session.IS_DIRECT_ACCESS] = "NO";
FormsAuthentication.RedirectFromLoginPage(loginForm.UserName, loginForm.RememberMeSet);
}
else
{
Logger.Log("User validation failed.", sClassName, sMethodName, DEBUG);
switch (iRetVal)
{
case -1:
loginForm.FailureText = Constant.Messages.INCORRECT_USER_OR_PASSWORD;
loginForm.Focus();
break;
case -2:
loginForm.FailureText = Constant.Messages.ACCOUNT_LOCKED;
loginForm.Focus();
break;
//case -3:
//TODO: Account doesn't exists
default:
var randToken = new Random().Next(1000);
Session[Constant.Session.TOKEN] = randToken;
var myHashtable = new Hashtable
{
{Constant.Session.TOKEN, randToken},
{Constant.Fields.ERROR_KEY, iRetVal}
};
Response.Redirect(WebFunctions.CreateQueryString(Constant.Urls.Error, myHashtable));
break;
}
}
}
我一直在检查会话是否不包含任何用户 ID,然后将其重定向到登录页面。我的母版页背后的代码如下:
protected void Page_Load(object sender, EventArgs e)
{
if (Session[Constant.Session.LOGIN_USER_ID] == null)
{
FormsAuthentication.RedirectToLoginPage();
return;
}
CheckDBConnection();
Initialize();
}
如有任何帮助或提示,我们将不胜感激。
您可以在此处查看该站点:www.paracha.net(如果有人感兴趣,我可以在私人消息中分享来宾帐户凭据)
如果您使用 FormsAuthentication,则无需手动检查 Session[Constant.Session.LOGIN_USER_ID]
。它将自动重定向到登录页面,您可以在 web.config.
中配置
另一个想法
与你的问题没有直接关系。这只是一种替代方法。
您可以创建自定义上下文来跟踪当前登录用户的信息,而不是创建多个会话状态
例如您可以将 Company 和 Fiscal Year 属性存储在 MyUser class.
中
void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (HttpContext.Current.User != null &&
HttpContext.Current.User.Identity.IsAuthenticated)
{
MyContext.Current.MyUser =
YOUR_BLL.GetUserByUsername(HttpContext.Current.User.Identity.Name);
}
}
public class MyContext
{
private MyUser _myUser;
public static MyContext Current
{
get
{
if (HttpContext.Current.Items["MyContext"] == null)
{
MyContext context = new MyContext();
HttpContext.Current.Items.Add("MyContext", context);
return context;
}
return (MyContext) HttpContext.Current.Items["MyContext"];
}
}
public MyUser MyUser
{
get { return _myUser; }
set { _myUser = value; }
}
}
}
加法
C#是强类型语言,所以你不应该用变量的类型来编码变量名。例如。 objLoginBLL 和 iRetVal。请阅读 C# 设计指南或 Essential C# 6.0 (Page 7).
首先,请记住会话 cookie 未加密,因此您不应使用会话来存储任何机密信息。
其次,您不应该在每个 Page_Load
上检查身份验证。相反,您应该在 web.config:
中配置页面访问
<configuration>
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</configuration>
这将保护您的所有页面,因此只有经过身份验证(即登录)的用户才能看到该页面,而所有其他用户将被重定向到登录页面。
如果您希望所有用户都可以访问某些页面(例如启动页面)或文件夹(例如图像文件夹),请为每个页面或文件夹添加一个部分:
<configuration>
<location path="splash.aspx">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
<location path="images">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
</configuration>
为了使其正常工作,您应该使用表单身份验证。下面是web.config中的设置:
<configuration>
<system.web>
<authentication mode="Forms">
<forms
name=".YOURNAME_AUTH"
loginUrl="login"
defaultUrl="/"
protection="All"
timeout="30"
path="/"
requireSSL="true"
slidingExpiration="true"
cookieless="UseCookies"
domain=""
enableCrossAppRedirects="false">
</forms>
</authentication>
</system.web>
</configuration>
显然,你需要一个login.aspx页面,当你点击登录按钮时,你需要像这样验证用户:
protected void btnLogIn_Click(object sender, EventArgs e) {
string Username = txtUsername.Text;
string Password = txtPassword.Text;
try {
if (ValidateUser(Username, Password)) {
FormsAuthentication.RedirectFromLoginPage(Username, false);
}
else {
lblMessage.Text = "Incorrect Credentials.";
lblMessage.ForeColor = Color.Red;
}
}
catch {
lblMessage.Text = "Login Failed.";
lblMessage.ForeColor = Color.Red;
}
}
函数ValidateUser()
可以做任何你想做的事情来进行身份验证。如果愿意,您可以根据数据库验证凭据。
我正在开发一个小型库存管理系统。我几乎已经在我的本地机器上创建了它。它按设计工作。我刚把它移到我的主机帐户,现在我遇到了一些问题。
1、登录后,当用户转到不同的页面时,打开和关闭表单,一段时间后重定向到登录页面。我不知道为什么。似乎发生了某种异常或会话为空。如何处理这种情况?
2,这是使用母版页的 Page_Load 事件检查用户登录的正确方法吗?
我的网站使用母版页,顶部导航菜单和底部正文区域具有单独的布局。当用户第一次登陆网站时,它会登录系统,成功登录后,我会将他的信息存储在会话中。为了添加、删除、更新目的,我在所有页面中大量使用 Session。执行添加记录时,我在会话中传递成功或失败消息以在 post 后显示。登录页面隐藏代码如下:
protected void loginForm_OnAuthenticate(object sender, AuthenticateEventArgs e)
{
string error = "";
sMethodName = "loginForm_OnAuthenticate";
_objLoginBLL = new LoginBLL();
int iRetVal = _objLoginBLL.ValidateUser(loginForm.UserName, loginForm.Password, ref error);
if (iRetVal >= 0)
{
Session.Clear(); //Remove all stored Session variables.
Session[Constant.Session.LOGGED_IN_DATETIME] = DateTime.Now.ToString("yyyyMMddHHmmssfff");
Session[Constant.Session.LOGIN_USERNAME] = loginForm.UserName;
Session[Constant.Session.LOGIN_USER_ID] = iRetVal;
Session[Constant.Session.LOGIN_COMPANY] = ddlCompanies.SelectedValue;
Session[Constant.Session.LOGIN_FISCAL_YEAR] = ddlFiscalYear.SelectedValue;
Session[Constant.Session.IS_DIRECT_ACCESS] = "NO";
FormsAuthentication.RedirectFromLoginPage(loginForm.UserName, loginForm.RememberMeSet);
}
else
{
Logger.Log("User validation failed.", sClassName, sMethodName, DEBUG);
switch (iRetVal)
{
case -1:
loginForm.FailureText = Constant.Messages.INCORRECT_USER_OR_PASSWORD;
loginForm.Focus();
break;
case -2:
loginForm.FailureText = Constant.Messages.ACCOUNT_LOCKED;
loginForm.Focus();
break;
//case -3:
//TODO: Account doesn't exists
default:
var randToken = new Random().Next(1000);
Session[Constant.Session.TOKEN] = randToken;
var myHashtable = new Hashtable
{
{Constant.Session.TOKEN, randToken},
{Constant.Fields.ERROR_KEY, iRetVal}
};
Response.Redirect(WebFunctions.CreateQueryString(Constant.Urls.Error, myHashtable));
break;
}
}
}
我一直在检查会话是否不包含任何用户 ID,然后将其重定向到登录页面。我的母版页背后的代码如下:
protected void Page_Load(object sender, EventArgs e)
{
if (Session[Constant.Session.LOGIN_USER_ID] == null)
{
FormsAuthentication.RedirectToLoginPage();
return;
}
CheckDBConnection();
Initialize();
}
如有任何帮助或提示,我们将不胜感激。
您可以在此处查看该站点:www.paracha.net(如果有人感兴趣,我可以在私人消息中分享来宾帐户凭据)
如果您使用 FormsAuthentication,则无需手动检查 Session[Constant.Session.LOGIN_USER_ID]
。它将自动重定向到登录页面,您可以在 web.config.
另一个想法
与你的问题没有直接关系。这只是一种替代方法。
您可以创建自定义上下文来跟踪当前登录用户的信息,而不是创建多个会话状态
例如您可以将 Company 和 Fiscal Year 属性存储在 MyUser class.
中void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (HttpContext.Current.User != null &&
HttpContext.Current.User.Identity.IsAuthenticated)
{
MyContext.Current.MyUser =
YOUR_BLL.GetUserByUsername(HttpContext.Current.User.Identity.Name);
}
}
public class MyContext
{
private MyUser _myUser;
public static MyContext Current
{
get
{
if (HttpContext.Current.Items["MyContext"] == null)
{
MyContext context = new MyContext();
HttpContext.Current.Items.Add("MyContext", context);
return context;
}
return (MyContext) HttpContext.Current.Items["MyContext"];
}
}
public MyUser MyUser
{
get { return _myUser; }
set { _myUser = value; }
}
}
}
加法
C#是强类型语言,所以你不应该用变量的类型来编码变量名。例如。 objLoginBLL 和 iRetVal。请阅读 C# 设计指南或 Essential C# 6.0 (Page 7).
首先,请记住会话 cookie 未加密,因此您不应使用会话来存储任何机密信息。
其次,您不应该在每个 Page_Load
上检查身份验证。相反,您应该在 web.config:
<configuration>
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</configuration>
这将保护您的所有页面,因此只有经过身份验证(即登录)的用户才能看到该页面,而所有其他用户将被重定向到登录页面。
如果您希望所有用户都可以访问某些页面(例如启动页面)或文件夹(例如图像文件夹),请为每个页面或文件夹添加一个部分:
<configuration>
<location path="splash.aspx">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
<location path="images">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
</configuration>
为了使其正常工作,您应该使用表单身份验证。下面是web.config中的设置:
<configuration>
<system.web>
<authentication mode="Forms">
<forms
name=".YOURNAME_AUTH"
loginUrl="login"
defaultUrl="/"
protection="All"
timeout="30"
path="/"
requireSSL="true"
slidingExpiration="true"
cookieless="UseCookies"
domain=""
enableCrossAppRedirects="false">
</forms>
</authentication>
</system.web>
</configuration>
显然,你需要一个login.aspx页面,当你点击登录按钮时,你需要像这样验证用户:
protected void btnLogIn_Click(object sender, EventArgs e) {
string Username = txtUsername.Text;
string Password = txtPassword.Text;
try {
if (ValidateUser(Username, Password)) {
FormsAuthentication.RedirectFromLoginPage(Username, false);
}
else {
lblMessage.Text = "Incorrect Credentials.";
lblMessage.ForeColor = Color.Red;
}
}
catch {
lblMessage.Text = "Login Failed.";
lblMessage.ForeColor = Color.Red;
}
}
函数ValidateUser()
可以做任何你想做的事情来进行身份验证。如果愿意,您可以根据数据库验证凭据。