但是,当我创建一个新用户时,我无法让它工作。当我这样做:
Membership.CreateUser(userName,password); Roles.AddUserToRole(userName,"MyRole");
创建用户并将其添加到数据库中的角色,但HttpContext.Current.User仍为空,Membership.GetUser()返回null,因此(来自Joel的代码)不起作用:
static public AccountProfile CurrentUser { get { return (AccountProfile) (ProfileBase.Create(Membership.GetUser().UserName)); } } AccountProfile.CurrentUser.FullName = "Snoopy";
我尝试调用Membership.GetUser(userName),并以这种方式设置Profile属性,但是set属性保持为空,并调用AccountProfile.CurrentUser(userName).Save()不会在数据库中放入任何东西。我也试过指出用户是有效的通过调用Membership.ValidateUser,FormsAuthentication.SetAuthCookie等登录,但当前用户仍然为空或匿名(取决于浏览器Cookie的状态)。
解决方案(再次参见下文):基于Franci Penov的解释和一些更多的实验,我想出了这个问题。 Joel的代码和我尝试的变体将只适用于现有的配置文件。如果没有Profile,ProfileBase.Create(userName)将在每次调用时返回一个新的空对象;您可以设置属性,但是它们不会“粘贴”,因为每次访问新实例时都会返回。将HttpContext.Current.User设置为新的GenericPrincipal将为您提供一个User对象,但不会提供Profile对象,而ProfileBase.Create(userName)和HttpContext.Current.Profile仍将指向新的空对象。
如果要在同一请求中为新创建的用户创建配置文件,则需要调用HttpContext.Current.Profile.Initialize(userName,true)。然后,您可以填充初始化的配置文件并将其保存,并且可以根据未来的请求按名称访问,因此Joel的代码将工作。我在内部只使用HttpContext.Current.Profile,当我需要在创建时立即创建/访问配置文件。在任何其他请求中,我使用ProfileBase.Create(userName),而且我已经公开了该版本。
请注意,Franci是正确的:如果您愿意创建用户(和角色),并将其设置为第一次往返验证,并要求用户登录,您将能够更简单地访问该配置文件通过Joel的代码对后续的请求。扔给我的是,用户创建后立即可以访问角色,无需任何初始化,但Profile不是。
我的新AccountProfile代码:
public static AccountProfile CurrentUser { get { if (Membership.GetUser() != null) return ProfileBase.Create(Membership.GetUser().UserName) as AccountProfile; else return null; } } internal static AccountProfile NewUser { get { return System.Web.HttpContext.Current.Profile as AccountProfile; } }
新用户创建:
MembershipUser user = Membership.CreateUser(userName,"MyBasicUserRole"); AccountProfile.NewUser.Initialize(userName,true); AccountProfile.NewUser.FullName = "Snoopy"; AccountProfile.NewUser.Save();
后续访问:
if (Membership.ValidateUser(userName,password)) { string name = AccountProfile.CurrentUser.FullName; }
进一步感谢Franci解释身份验证生命周期 – 我在验证函数中调用FormsAuthentication.SetAuthCookie,但是我返回一个bool来指示成功,因为在后续请求之后,User.Identity.IsAuthenticated将不会为true。
修改:我是个白痴上述说明在狭义的情况下工作,但不解决核心问题:Calling CurrentUser每次返回对象的新实例,无论它是否是现有的Profile。因为它被定义为一个财产,我没有想到这个,并写道:
AccountProfile.CurrentUser.FullName = "Snoopy"; AccountProfile.CurrentUser.OtherProperty = "ABC"; AccountProfile.CurrentUser.Save();
这当然不行。它应该是:
AccountProfile currentProfile = AccountProfile.CurrentUser; currentProfile.FullName = "Snoopy"; currentProfile.OtherProperty = "ABC"; currentProfile.Save();
完全忽略这个基本点是我自己的错,但我认为将CurrentUser声明为属性意味着它是一个可以被操纵的对象。而应该被声明为GetCurrentUser()。
解决方法
Membership.ValidateUser只会验证凭据,但不会对当前或后续请求的用户进行身份验证。 FormsAuthentication.SetAuthCookie将在响应流中设置认证凭证,因此下一个请求将被认证,但不会影响当前请求的状态。
验证用户最简单的方法是调用FormsAuthentication.RedirectFromLoginPage(假设您在应用程序中使用表单验证)。但是,这实际上会导致一个新的HTTP请求,它将验证用户。
或者,如果您需要继续处理当前请求的逻辑,但希望用户进行身份验证,则可以创建一个GenericPrincipal,为其分配新用户的身份,并将HttpContext.User设置为该主体。