使用asp.net成员关系和MVC概要文件,如何创建用户并将其设置为HttpContext.Current.User?

时间:2023-01-26 01:40:24

I implemented a custom Profile object in code as described by Joel here:

我在代码中实现了一个自定义配置文件对象,如Joel在这里所描述的:

How to assign Profile values?

如何分配配置文件值?

I can't get it to work when I'm creating a new user, however. When I do this:

然而,当我创建一个新用户时,我无法让它工作。当我这样做:

Membership.CreateUser(userName, password);
Roles.AddUserToRole(userName, "MyRole");

the user is created and added to a role in the database, but HttpContext.Current.User is still empty, and Membership.GetUser() returns null, so this (from Joel's code) doesn't work:

用户被创建并添加到数据库中的角色,但是HttpContext.Current。User仍然是空的,而Membership.GetUser()返回null,因此这个(来自Joel的代码)不起作用:

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

AccountProfile.CurrentUser.FullName = "Snoopy";

I've tried calling Membership.GetUser(userName) and setting Profile properties that way, but the set properties remain empty, and calling AccountProfile.CurrentUser(userName).Save() doesn't put anything in the database. I've also tried indicating that the user is valid & logged in, by calling Membership.ValidateUser, FormsAuthentication.SetAuthCookie, etc., but the current user is still null or anonymous (depending on the state of my browser cookies).

我尝试过调用Membership.GetUser(userName)并以这种方式设置配置文件属性,但是设置属性仍然为空,并且调用AccountProfile.CurrentUser(userName). save()不会在数据库中放入任何内容。我还尝试通过调用Membership来指示用户是有效的&登录的。ValidateUser FormsAuthentication。SetAuthCookie等,但是当前用户仍然是null或匿名的(取决于浏览器cookie的状态)。

SOLVED (EDITED FURTHER, SEE BELOW): Based on Franci Penov's explanation and some more experimentation, I figured out the issue. Joel's code and the variations I tried will only work with an existing Profile. If no Profile exists, ProfileBase.Create(userName) will return a new empty object every time it's called; you can set properties, but they won't "stick" because a new instance is returned every time you access it. Setting HttpContext.Current.User to a new GenericPrincipal will give you a User object, but not a Profile object, and ProfileBase.Create(userName) and HttpContext.Current.Profile will still point to new, empty objects.

解决(进一步编辑,见下文):基于Franci Penov的解释和更多的实验,我解决了这个问题。乔尔的代码和我尝试过的变体只适用于现有的概要文件。如果没有概要文件存在,那么ProfileBase.Create(userName)将在每次调用时返回一个新的空对象;您可以设置属性,但它们不会“粘住”,因为每次访问一个新实例时都会返回它。设置HttpContext.Current。新GenericPrincipal的用户将为您提供一个用户对象,而不是配置文件对象,以及Profile base . create(用户名)和HttpContext.Current。配置文件仍然指向新的空对象。

If you want to create a Profile for a newly-created User in the same request, you need to call HttpContext.Current.Profile.Initialize(userName, true). You can then populate the initialized profile and save it, and it will be accessible on future requests by name, so Joel's code will work. I am only using HttpContext.Current.Profile internally, when I need to create/access the Profile immediately upon creation. On any other requests, I use ProfileBase.Create(userName), and I've exposed only that version as public.

如果您想在同一个请求中为新创建的用户创建一个概要文件,您需要调用HttpContext.Current.Profile。初始化(用户名、真实)。然后,您可以填充初始化的概要文件并将其保存,在以后的请求中可以按名称访问它,因此Joel的代码将会工作。我只使用HttpContext.Current。在内部配置文件时,当我需要在创建时立即创建/访问配置文件。对于任何其他请求,我都使用profile . create(用户名),并且我只公开该版本。

Note that Franci is correct: If you are willing to create the User (and Roles) and set it as Authenticated on the first round-trip, and ask the user to then log in, you will be able to access the Profile much more simply via Joel's code on the subsequent request. What threw me is that Roles is immediately accessible upon user creation without any initialization, but Profile is not.

注意,Franci是正确的:如果您愿意创建用户(和角色),并在第一次往返时将其设置为已验证,并请求用户登录,那么您将能够通过Joel的代码在后续请求中更简单地访问配置文件。让我吃惊的是,角色在用户创建时是可以立即访问的,不需要任何初始化,但是Profile不是。

My new AccountProfile code:

我的新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; }
}

New user creation:

新用户创建:

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

Subsequent access:

随后的访问:

if (Membership.ValidateUser(userName, password))
{
    string name = AccountProfile.CurrentUser.FullName;
}

Further thanks to Franci for explaining the Authentication life cycle - I'm calling FormsAuthentication.SetAuthCookie in my validation function, but I'm returning a bool to indicate success, because User.Identity.IsAuthenticated will not be true until the subsequent request.

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

REVISED: I'm an idiot. The above explanation works in the narrow case, but doesn't resolve the core problem: Calling CurrentUser returns a new instance of the object each time, whether it's an existing Profile or not. Because it's defined as a property, I wasn't thinking about this, and wrote:

修改:我是一个白痴。上述解释适用于较窄的情况,但不能解决核心问题:每次调用CurrentUser都会返回一个对象的新实例,不管它是否是现有的概要文件。因为它被定义为一个属性,我没有考虑这个,并写道

AccountProfile.CurrentUser.FullName = "Snoopy";
AccountProfile.CurrentUser.OtherProperty = "ABC";
AccountProfile.CurrentUser.Save();

which (of course) doesn't work. It should be:

这(当然)是行不通的。应该是:

AccountProfile currentProfile = AccountProfile.CurrentUser;
currentProfile.FullName = "Snoopy";
currentProfile.OtherProperty = "ABC";
currentProfile.Save();

It's my own fault for completely overlooking this basic point, but I do think declaring CurrentUser as a property implies that it's an object that can be manipulated. Instead, it should be declared as GetCurrentUser().

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

3 个解决方案

#1


7  

Creating a user just adds it to the list of users. However, this does not authenticate or authorize the new user for the current request. You also need to authenticate the user in the current request context or for subsequent requests.

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

Membership.ValidateUser will only validate the credentials, but it's not authenticating the user for the current or subsequent requests. FormsAuthentication.SetAuthCookie will set the authentication ticket in the response stream, so the next request will be authenticated, but it does not affect the state of the current request.

成员资格。ValidateUser只会验证凭据,但它不会对当前或后续请求的用户进行验证。FormsAuthentication。SetAuthCookie将在响应流中设置身份验证标签,因此下一个请求将被验证,但它不会影响当前请求的状态。

The easiest way to authenticate the user would be to call FormsAuthentication.RedirectFromLoginPage (assuming you are using forms authentication in your app). However, this one would actually cause a new HTTP request, which will authenticate the user.

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

Alternatively, if you need to continue your logic for processing the current request, but want the user to be authenticated, you can create a GenericPrincipal, assign it the identity of the new user and set the HttpContext.User to that principal.

另外,如果您需要继续处理当前请求的逻辑,但是希望对用户进行身份验证,您可以创建一个GenericPrincipal,为它分配新用户的标识,并设置HttpContext。主要的用户。

#2


1  

You are going to run into problems with this approach if you enable anonymousIdentification. Rather than Membership.GetUser().UserName, I would suggest using HttpContext.Profile.UserName.

如果您启用匿名身份验证,那么您将会遇到这种方法的问题。而不是Membership.GetUser()。用户名,我建议使用HttpContext.Profile.UserName。

Like this...

像这样…

private UserProfile _profile;
private UserProfile Profile
{
    get { return _profile ?? (_profile = (UserProfile)ProfileBase.Create(HttpContext.Profile.UserName)); }
}

Hat tip: SqlProfileProvider - can you use Profile.GetProfile() in a project?

帽提示:SqlProfileProvider -您能在项目中使用Profile.GetProfile()吗?

#3


0  

First of all, thanks @Jeremy for sharing your findings. You helped me get going in the right direction. Secondly, sorry for bumping this old post. Hopefully this will help someone connect the dots.

首先,感谢@Jeremy分享你的发现。你帮我找到了正确的方向。第二,很抱歉撞到这个旧帖子。希望这能帮助人们将这些联系起来。

The way I finally got this working was to use the following static method inside my profile class:

我最终实现这个功能的方法是在我的profile类中使用以下静态方法:

internal static void InitializeNewMerchant(string username, Merchant merchant)
{
    var profile = System.Web.HttpContext.Current.Profile as MerchantProfile;
    profile.Initialize(username, true);
    profile.MerchantId = merchant.MerchantId;
    profile.Save();
}

#1


7  

Creating a user just adds it to the list of users. However, this does not authenticate or authorize the new user for the current request. You also need to authenticate the user in the current request context or for subsequent requests.

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

Membership.ValidateUser will only validate the credentials, but it's not authenticating the user for the current or subsequent requests. FormsAuthentication.SetAuthCookie will set the authentication ticket in the response stream, so the next request will be authenticated, but it does not affect the state of the current request.

成员资格。ValidateUser只会验证凭据,但它不会对当前或后续请求的用户进行验证。FormsAuthentication。SetAuthCookie将在响应流中设置身份验证标签,因此下一个请求将被验证,但它不会影响当前请求的状态。

The easiest way to authenticate the user would be to call FormsAuthentication.RedirectFromLoginPage (assuming you are using forms authentication in your app). However, this one would actually cause a new HTTP request, which will authenticate the user.

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

Alternatively, if you need to continue your logic for processing the current request, but want the user to be authenticated, you can create a GenericPrincipal, assign it the identity of the new user and set the HttpContext.User to that principal.

另外,如果您需要继续处理当前请求的逻辑,但是希望对用户进行身份验证,您可以创建一个GenericPrincipal,为它分配新用户的标识,并设置HttpContext。主要的用户。

#2


1  

You are going to run into problems with this approach if you enable anonymousIdentification. Rather than Membership.GetUser().UserName, I would suggest using HttpContext.Profile.UserName.

如果您启用匿名身份验证,那么您将会遇到这种方法的问题。而不是Membership.GetUser()。用户名,我建议使用HttpContext.Profile.UserName。

Like this...

像这样…

private UserProfile _profile;
private UserProfile Profile
{
    get { return _profile ?? (_profile = (UserProfile)ProfileBase.Create(HttpContext.Profile.UserName)); }
}

Hat tip: SqlProfileProvider - can you use Profile.GetProfile() in a project?

帽提示:SqlProfileProvider -您能在项目中使用Profile.GetProfile()吗?

#3


0  

First of all, thanks @Jeremy for sharing your findings. You helped me get going in the right direction. Secondly, sorry for bumping this old post. Hopefully this will help someone connect the dots.

首先,感谢@Jeremy分享你的发现。你帮我找到了正确的方向。第二,很抱歉撞到这个旧帖子。希望这能帮助人们将这些联系起来。

The way I finally got this working was to use the following static method inside my profile class:

我最终实现这个功能的方法是在我的profile类中使用以下静态方法:

internal static void InitializeNewMerchant(string username, Merchant merchant)
{
    var profile = System.Web.HttpContext.Current.Profile as MerchantProfile;
    profile.Initialize(username, true);
    profile.MerchantId = merchant.MerchantId;
    profile.Save();
}