表单身份验证 Cookie 在服务器关闭/故障时不会过期
这是我使用 CustomMembershipProvider 登录的用例
- 用户登录 MembershipProvider 验证用户帐户
- Membership 的用户属性设置为来自数据库的用户详细信息
- 创建身份验证票证
- 添加表单身份验证 cookie。
- 用户已登录
这是我的问题的一个用例
- 停止 Web 开发服务器
- 启动 Web 开发服务器,并且用户仍然登录(由于 cookie?)
- 由于服务器重新启动/故障,用户属性成员资格设置为 null
- 应用程序抛出由于空用户值而导致的异常
我能想到的唯一解决方案是清除 Application_Start() 上的所有 cookie,但我不知道这怎么可能,因为请求在应用程序启动期间脱离了上下文。
您对如何解决此类问题有什么想法吗?
这是代码:
CustomMembershipProvider
public class CustomMembershipProvider : MembershipProvider
{
#region Unimplemented MembershipProvider Methods
//Other methods here
#endregion
//private IUserRepository _userRepository = new UserRepository();
//Ninject bindings
private IUserRepository _userRepository;
[Inject]
public IUserRepository UserRepository
{
set
{
_userRepository = value;
}
}
private IProfileRepository _profileRepository;
[Inject]
public IProfileRepository ProfileRepository
{
set
{
_profileRepository = value;
}
}
public User User
{
get;
private set;
}
public Profile Profile
{
get;
set;
}
public CustomMembershipProvider()
{
MvcApplication.Container.Inject(this);
}
public override bool ValidateUser(string username, string password)
{
if (string.IsNullOrEmpty(password.Trim())) return false;
User user = _userRepository.GetUserByUsername(username);
user.UserType = UserHelper.GetUserTypeById(user.UserTypeId);
if (user == null) return false;
string hash = PasswordHelper.ComputeHash(password, user.PasswordSalt);
if (user.Password == hash)
{
this.User = user;
Profile profile = _profileRepository.GetProfileByUserId(user.UserId);
this.Profile = profile;
return true;
}
return false;
}
}
这是帐户控制器的登录方法
[HttpPost]
public ActionResult Login(string username, string password)
{
if (!provider.ValidateUser(username, password))
{
TempData["LoginError"] = "Incorrect";
}
else
{
User user = provider.User;
if (!user.Verified)
{
TempData["LoginError"] = "Please verify your account";
return Redirect(Request.UrlReferrer.LocalPath);
}
//FormsAuthentication.SetAuthCookie(user.Username,false);
FormsAuthenticationTicket authTicket = new
FormsAuthenticationTicket(1, //version
username, //user name
DateTime.Now, //creation
DateTime.Now.AddMinutes(30), //Expiration
false, //Persistent
username); //since Classic logins don't have a "Friendly Name"
string encTicket = FormsAuthentication.Encrypt(authTicket);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
WebsiteObjects.Profile profile = provider.Profile;
TempData["LoginError"] = String.Empty;
}
return Redirect("/");
}
下面的建议是不可行的,因为每当我重新启动服务器时都会出现这种情况。
- Application_BeginRequest 上的 Request.IsAuthenticated 为 FALSE;
- Request.IsAuthenticated 在我的“视图”上为 TRUE
为什么会发生这种情况?
Here is a use case of my login using a CustomMembershipProvider
- User Logs in MembershipProvider validates user account
- User property of Membership is set to user details coming from the database
- An authentication ticket is created
- Forms authentication cookie is added.
- User is logged in
Here is a use case of my problem
- Stop whe web development server
- Start the web development server, and user is still logged in (due to cookie?)
- User property Membership is set to null due to server restart/failure
- Application throws exception due to null user value
The only solution I could think off is to clear all cookies on Application_Start() but I don't know how is that even possible as Request is out of context during application start.
Do you have any ideas how to solve this kind of problem?
Here is the code:
CustomMembershipProvider
public class CustomMembershipProvider : MembershipProvider
{
#region Unimplemented MembershipProvider Methods
//Other methods here
#endregion
//private IUserRepository _userRepository = new UserRepository();
//Ninject bindings
private IUserRepository _userRepository;
[Inject]
public IUserRepository UserRepository
{
set
{
_userRepository = value;
}
}
private IProfileRepository _profileRepository;
[Inject]
public IProfileRepository ProfileRepository
{
set
{
_profileRepository = value;
}
}
public User User
{
get;
private set;
}
public Profile Profile
{
get;
set;
}
public CustomMembershipProvider()
{
MvcApplication.Container.Inject(this);
}
public override bool ValidateUser(string username, string password)
{
if (string.IsNullOrEmpty(password.Trim())) return false;
User user = _userRepository.GetUserByUsername(username);
user.UserType = UserHelper.GetUserTypeById(user.UserTypeId);
if (user == null) return false;
string hash = PasswordHelper.ComputeHash(password, user.PasswordSalt);
if (user.Password == hash)
{
this.User = user;
Profile profile = _profileRepository.GetProfileByUserId(user.UserId);
this.Profile = profile;
return true;
}
return false;
}
}
Here is the login method of the Account Controller
[HttpPost]
public ActionResult Login(string username, string password)
{
if (!provider.ValidateUser(username, password))
{
TempData["LoginError"] = "Incorrect";
}
else
{
User user = provider.User;
if (!user.Verified)
{
TempData["LoginError"] = "Please verify your account";
return Redirect(Request.UrlReferrer.LocalPath);
}
//FormsAuthentication.SetAuthCookie(user.Username,false);
FormsAuthenticationTicket authTicket = new
FormsAuthenticationTicket(1, //version
username, //user name
DateTime.Now, //creation
DateTime.Now.AddMinutes(30), //Expiration
false, //Persistent
username); //since Classic logins don't have a "Friendly Name"
string encTicket = FormsAuthentication.Encrypt(authTicket);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
WebsiteObjects.Profile profile = provider.Profile;
TempData["LoginError"] = String.Empty;
}
return Redirect("/");
}
Suggestions below are not doable because whenever I restart the server here is the case.
- Request.IsAuthenticated is FALSE on Application_BeginRequest;
- Request.IsAuthenticated is TRUE on my 'View'
why is this happening?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您应该对每个请求执行步骤 2,或将用户详细信息存储到身份验证 cookie 的 UserData 部分。
You should perform step 2 on each request or store the user details into the UserData part of the authentication cookie.
在 Application_AuthenticateRequest 中检查 Request.IsAuthenticated=true 但 User 对象是否为 null,然后重新填充它。
In the Application_AuthenticateRequest check if Request.IsAuthenticated=true but User object is null then re-populate it.