Используя ASP .Сетевое членство и профиль с помощью MVC, как я могу создать пользователя и установить для него значение HttpContext.Current.Пользователь?

StackOverflow https://stackoverflow.com/questions/2547290

Вопрос

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

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

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

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

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

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 будет предоставить вам пользовательский объект, но не объект профиля, и 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.Установите AuthCookie в моей функции проверки, но я возвращаю bool для указания успеха, потому что User.Идентификатор.IsAuthenticated не будет иметь значения true до последующего запроса.

ПЕРЕСМОТРЕННЫЙ: Я идиот.Приведенное выше объяснение работает в узком случае, но не решает основную проблему:Вызов 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().

Это было полезно?

Решение

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

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

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

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

Другие советы

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

Вот так...

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

Кончик шляпы: SqlProfileProvider - можете ли вы использовать Profile.getProfile() в проекте?

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

Способ, которым я, наконец, заставил это работать, заключался в использовании следующего статического метода внутри моего класса 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();
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top