2010-03-30 1 views
17

я реализовал пользовательский профиль объекта в коде, как описано Joel здесь:Использование членства ASP.NET и профиля с MVC, как я могу создать пользователя и установить его в HttpContext.Current.User?

How to assign Profile values?

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

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 моего браузера).

SOLVED (ИЗОБРАЖЕН ДАЛЬШЕ, ВИДЕТЬ НИЖЕ): Основываясь на объяснениях Франци Пенова и некоторых дополнительных экспериментах, я выяснил эту проблему. Код Джоэля и варианты, которые я пробовал, будут работать только с существующим профилем. Если профиль отсутствует, 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), и я раскрыл только эту версию как общедоступную.

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

Мой новый код АккаунтПрофиль:

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; 
} 

Далее благодаря Франки для объяснения жизни Authentication цикла - I» m вызывает FormsAuthentication.SetAuthCookie в моей функции проверки, но я возвращаю bo ol, чтобы указать успех, поскольку 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().

ответ

7

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

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

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

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

+0

Будет ли эта работа выдает себя за другого пользователя, а? –

+0

Олицетворение обычно подразумевает проверку подлинности Windows, для которой требуется WindowsPrincipal. Олицетворение может быть сделано из маркера безопасности для олицетворенного пользователя или из учетных данных. Учитывая, что текущий контекст не аутентифицирован, возможно, нет способа получить токен безопасности для пользователя. Таким образом, единственный выбор олицетворяет учетные данные. Возможно, можно создать WindowsPrincipal с надлежащей идентификацией, вызвав LogonUser (если код знает учетные данные для пользователя Windows). Тем не менее, я не пробовал это, поэтому я не могу ручаться, это обязательно сработает. –

+0

Это невероятно полезное объяснение, спасибо.Создание GenericPrincipal (из моего FormsAuthenticationTicket) позволило мне установить HttpContext.Current.User. Тем не менее, я все еще не могу установить значения профиля. Если я использую ProfileBase.Create (Membership.GetUser(). UserName) .SetPropertyValue, ничего не происходит - он больше не генерирует исключение, но свойство остается пустым. Если я использую HttpContext.Current.Profile.SetPropertyValue, он говорит, что я не могу установить свойства в анонимном профиле, подразумевая, что это разные объекты профиля, которые мне как-то нужно объединить. –

0

Прежде всего, спасибо @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(); 
} 
1

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

Как это ...

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

Hat совет: SqlProfileProvider - can you use Profile.GetProfile() in a project?