Используя членство и профиль ASP .NET с MVC, как я могу создать пользователя и установить для него значение HttpContext.Current.User? - PullRequest
17 голосов
/ 30 марта 2010

Я реализовал пользовательский объект Profile в коде, как описано Джоэлем здесь:

Как назначить значения профиля?

Однако я не могу заставить его работать, когда создаю нового пользователя. Когда я делаю это:

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

пользователь создан и добавлен к роли в базе данных, но HttpContext.Current.User все еще пуст, а Membership.GetUser() возвращает ноль, так что это (из кода Джоэла) не работает:

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

AccountProfile.CurrentUser.FullName = "Snoopy";

Я пытался вызвать Membership.GetUser(userName) и установить таким образом свойства профиля, но установленные свойства остаются пустыми, а вызов AccountProfile.CurrentUser(userName).Save() ничего не помещает в базу данных. Я также пытался указать, что пользователь действителен и вошел в систему, позвонив по номеру Membership.ValidateUser, FormsAuthentication.SetAuthCookie и т. Д., Но текущий пользователь по-прежнему является нулевым или анонимным (в зависимости от состояния файлов cookie моего браузера).

решено (отредактировано, см. Ниже): Основываясь на объяснениях Франци Пенова и еще нескольких экспериментах, я выяснил проблему. Код Джоэла и варианты, которые я попробовал, будут работать только с существующим профилем. Если профиль не существует, ProfileBase.Create(userName) будет возвращать новый пустой объект каждый раз, когда он вызывается; Вы можете установить свойства, но они не будут «прилипать», потому что новый экземпляр возвращается каждый раз, когда вы обращаетесь к нему. Установка HttpContext.Current.User на новый GenericPrincipal даст объект User, но not объект профиля, а ProfileBase.Create(userName) и HttpContext.Current.Profile будут все еще указывать на новый, пустой объекты.

Если вы хотите создать профиль для вновь созданного пользователя по тому же запросу, вам нужно позвонить HttpContext.Current.Profile.Initialize(userName, true). Затем вы можете заполнить инициализированный профиль и сохранить его, и он будет доступен для будущих запросов по имени, поэтому код Джоэла будет работать. Я только , использую HttpContext.Current.Profile для внутреннего использования, когда мне нужно создать / получить доступ к профилю сразу после создания. В любых других запросах я использую ProfileBase.Create(userName), и я выставил только эту версию как общедоступную.

Обратите внимание, что Франси прав: если вы хотите создать пользователя (и роли) и установить его как Аутентифицированный в первом круговом обращении, а затем попросить пользователя войти в систему, вы сможете получить доступ к профилю. гораздо проще через код Джоэла по последующему запросу. Меня бросило то, что роли сразу же становятся доступны при создании пользователя без какой-либо инициализации, но профиль - нет.

Мой новый аккаунтКод профиля:

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, password);
Roles.AddUserToRole(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 в моей функции проверки, но я возвращаю логическое значение, указывающее на успех, потому что User.Identity.IsAuthenticated не будет истинным до следующего запрос.

ПЕРЕСМОТРЕНО: Я идиот. Вышеприведенное объяснение работает в узком случае, но не решает основной проблемы: вызов CurrentUser каждый раз возвращает новый экземпляр объекта, независимо от того, является ли он существующим профилем или нет. Поскольку это определяется как свойство, я не думал об этом и написал:

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().

Ответы [ 3 ]

7 голосов
/ 30 марта 2010

Создание пользователя просто добавляет его в список пользователей. Однако это не аутентифицирует и не авторизует нового пользователя для текущего запроса. Вам также необходимо аутентифицировать пользователя в текущем контексте запроса или для последующих запросов.

Membership.ValidateUser только проверяет учетные данные, но не проверяет подлинность пользователя для текущих или последующих запросов. FormsAuthentication.SetAuthCookie установит билет аутентификации в потоке ответов, поэтому следующий запрос будет аутентифицирован, но это не повлияет на состояние текущего запроса.

Самый простой способ аутентификации пользователя - позвонить по номеру FormsAuthentication.RedirectFromLoginPage (при условии, что вы используете аутентификацию с помощью форм в своем приложении). Однако этот вызов фактически вызовет новый HTTP-запрос, который будет аутентифицировать пользователя.

В качестве альтернативы, если вам нужно продолжить свою логику для обработки текущего запроса, но вы хотите, чтобы пользователь прошел аутентификацию, вы можете создать GenericPrincipal, назначить ему идентификатор нового пользователя и установить для него HttpContext.User главный.

1 голос
/ 22 января 2012

При таком подходе у вас возникнут проблемы, если вы включите anonymousIdentification. Вместо Membership.GetUser (). UserName я бы предложил использовать HttpContext.Profile.UserName.

Вот так ...

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

Подсказка: SqlProfileProvider - можете ли вы использовать Profile.GetProfile () в проекте?

0 голосов
/ 02 июля 2011

Прежде всего, спасибо @Jeremy за то, что поделились своими выводами. Вы помогли мне двигаться в правильном направлении. Во-вторых, извините за натыкаясь на этот старый пост. Надеюсь, это поможет кому-то соединить точки.

То, как я наконец получил эту работу, заключалось в использовании следующего статического метода внутри моего профиля:

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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...