使用ASP .NET Membership和Profile with MVC,如何创建用户并将其设置为HttpContext.Current.User?

Jer*_*ald 17 membership profile asp.net-mvc createuser

我在代码中实现了一个自定义的Profile对象,如Joel所述:

如何分配配置文件值?

但是,当我创建一个新用户时,我无法让它工作.当我这样做:

Membership.CreateUser(userName, password);
Roles.AddUserToRole(userName, "MyRole");
Run Code Online (Sandbox Code Playgroud)

用户是创建并添加到数据库中的角色,但HttpContext.Current.User仍然是空的,并Membership.GetUser()返回null,所以这(从Joel的代码)不起作用:

static public AccountProfile CurrentUser
{
    get { return (AccountProfile)
                     (ProfileBase.Create(Membership.GetUser().UserName)); }
}

AccountProfile.CurrentUser.FullName = "Snoopy";
Run Code Online (Sandbox Code Playgroud)

我尝试过这样调用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是正确的:如果您愿意创建用户(和角色)并在第一次往返时将其设置为Authenticated,并要求用户再登录,您将能够更简单地访问该配置文件通过Joel的代码来处理后续请求.让我感到震惊的是,Roles可以在用户创建时立即访问,无需任何初始化,但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; }
}
Run Code Online (Sandbox Code Playgroud)

新用户创建:

MembershipUser user = Membership.CreateUser(userName, password);
Roles.AddUserToRole(userName, "MyBasicUserRole");
AccountProfile.NewUser.Initialize(userName, true);
AccountProfile.NewUser.FullName = "Snoopy";
AccountProfile.NewUser.Save();
Run Code Online (Sandbox Code Playgroud)

后续访问:

if (Membership.ValidateUser(userName, password))
{
    string name = AccountProfile.CurrentUser.FullName;
}
Run Code Online (Sandbox Code Playgroud)

进一步感谢Franci解释身份验证生命周期 - 我在验证函数中调用了FormsAuthentication.SetAuthCookie,但我返回一个bool来表示成功,因为User.Identity.IsAuthenticated在后续请求之前不会成立.

修订:我是个白痴.以上解释适用于狭义的情况,但不能解决核心问题:每次调用CurrentUser都会返回一个新的对象实例,无论它是否是现有的Profile.因为它被定义为属性,我没有考虑这个,并写道:

AccountProfile.CurrentUser.FullName = "Snoopy";
AccountProfile.CurrentUser.OtherProperty = "ABC";
AccountProfile.CurrentUser.Save();
Run Code Online (Sandbox Code Playgroud)

哪(当然)不起作用.它应该是:

AccountProfile currentProfile = AccountProfile.CurrentUser;
currentProfile.FullName = "Snoopy";
currentProfile.OtherProperty = "ABC";
currentProfile.Save();
Run Code Online (Sandbox Code Playgroud)

完全忽略这个基本点是我自己的错,但我确实认为将CurrentUser声明为属性意味着它是一个可以被操纵的对象.相反,它应该声明为GetCurrentUser().

Fra*_*nov 7

创建用户只需将其添加到用户列表中.但是,这不会对当前请求的新用户进行身份验证或授权.您还需要在当前请求上下文或后续请求中对用户进行身份验证.

Membership.ValidateUser将仅验证凭据,但不会对当前或后续请求的用户进行身份验证.FormsAuthentication.SetAuthCookie将在响应流中设置身份验证票证,以便对下一个请求进行身份验证,但不会影响当前请求的状态.

验证用户的最简单方法是调用FormsAuthentication.RedirectFromLoginPage(假设您在应用程序中使用表单身份验证).但是,这个实际上会导致新的HTTP请求,该请求将对用户进行身份验证.

或者,如果您需要继续处理当前请求的逻辑,但希望对用户进行身份验证,则可以创建a GenericPrincipal,为其分配新用户的标识并将其设置HttpContext.User为该主体.