2010-03-30 11 views
17

he implementado un objeto personalizado del perfil en el código como se describe por Joel aquí:Usando membresía y perfil de ASP .NET con MVC, ¿cómo puedo crear un usuario y configurarlo en HttpContext.Current.User?

How to assign Profile values?

no puedo conseguir que funcione cuando estoy creando un nuevo usuario, sin embargo. Cuando hago esto:

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

el usuario se crea y se añade a un papel en la base de datos, pero HttpContext.Current.User sigue vacío, y Membership.GetUser() vuelve nula, por lo que este (a partir del código de Joel) no funciona:

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

AccountProfile.CurrentUser.FullName = "Snoopy"; 

he intentado llamar Membership.GetUser(userName) y configuración de propiedades del perfil de esa manera, pero las propiedades de deformación permanecen vacías, y llamando AccountProfile.CurrentUser(userName).Save() no ponga nada en la base de datos. También intenté indicar que el usuario es válido &, inicie sesión, llamando al Membership.ValidateUser, FormsAuthentication.SetAuthCookie, etc., pero el usuario actual sigue siendo nulo o anónimo (dependiendo del estado de las cookies de mi navegador).

RESUELTO (EDITADO MÁS ADELANTE, VEA A CONTINUACIÓN): Basado en la explicación de Franci Penov y un poco más de experimentación, descubrí el problema. El código de Joel y las variaciones que probé solo funcionarán con un perfil existente. Si no existe ningún perfil, ProfileBase.Create(userName) devolverá un nuevo objeto vacío cada vez que se llame; puede establecer propiedades, pero no se "pegarán" porque se devuelve una nueva instancia cada vez que accede a ella. Configuración HttpContext.Current.User a un nuevo GenericPrincipal se le dará un objeto de usuario, pero no un objeto Perfil, y ProfileBase.Create(userName) y HttpContext.Current.Profile todavía apuntará a nuevos objetos, vacías.

Si desea crear un perfil para un usuario recién creado en la misma solicitud, debe llamar al HttpContext.Current.Profile.Initialize(userName, true). A continuación, puede completar el perfil inicializado y guardarlo, y estará accesible en solicitudes futuras por nombre, para que el código de Joel funcione. Estoy solo usando HttpContext.Current.Profile internamente, cuando necesito crear/acceder al Perfil inmediatamente después de la creación. En cualquier otra solicitud, uso ProfileBase.Create(userName) y expuse solo esa versión como pública.

Tenga en cuenta que Franci es correcta: si está dispuesto a crear el Usuario (y Roles) y establecerlo como Autenticado en el primer viaje de ida y vuelta, y le pide al usuario que inicie sesión, podrá acceder al Perfil mucho más simple a través del código de Joel en la solicitud posterior. Lo que me impresionó es que se puede acceder inmediatamente a Roles al crear el usuario sin ninguna inicialización, pero Profile no lo está.

Mi nuevo código 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; } 
} 

Nueva creación del usuario:

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

El acceso posterior:

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

aún más gracias a Franci para explicar el ciclo de vida de autenticación - I' Estoy llamando a FormsAuthentication.SetAuthCookie en mi función de validación, pero estoy devolviendo un bo ol para indicar el éxito, porque User.Identity.IsAuthenticated no será verdadero hasta la solicitud posterior.

REVISADO: Soy un idiota. La explicación anterior funciona en el caso estrecho, pero no resuelve el problema de fondo: Llamada CurrentUser devuelve una nueva instancia del objeto cada vez, si se trata de un perfil existente o no. Debido a que se define como una propiedad, no estaba pensando en esto, y escribió:

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

la que (por supuesto) no funciona. Debe ser:

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

Es mi propia culpa por pasar por alto por completo este punto básico, pero yo creo que se declara CurrentUser como una propiedad implica que se trata de un objeto que puede ser manipulada. En cambio, debe declararse como GetCurrentUser().

Respuesta

7

Creación de un usuario sólo se suma a la lista de usuarios. Sin embargo, esto no autentica ni autoriza al nuevo usuario para la solicitud actual. También necesita autenticar al usuario en el contexto de solicitud actual o para solicitudes posteriores.

Membership.ValidateUser solo validará las credenciales, pero no está autenticando al usuario para las solicitudes actuales o subsiguientes. FormsAuthentication.SetAuthCookie establecerá el vale de autenticación en la secuencia de respuesta, por lo que será autenticado la siguiente petición, pero no afecta el estado de la solicitud actual.

La forma más fácil de autenticar al usuario sería llamar al FormsAuthentication.RedirectFromLoginPage (suponiendo que está utilizando la autenticación de formularios en su aplicación). Sin embargo, esto realmente causaría una nueva solicitud HTTP, que autenticará al usuario.

Alternativamente, si necesita continuar su lógica para procesar la solicitud actual, pero desea que el usuario sea autenticado, puede crear un GenericPrincipal, asignarle la identidad del nuevo usuario y establecer el HttpContext.User en ese principal.

+0

¿Este trabajo por hacerse pasar por otro usuario, así? –

+0

suplantación por lo general implica la autenticación de Windows, lo que requiere un WindowsPrincipal. La suplantación se puede hacer desde el token de seguridad para el usuario suplantado o desde las credenciales. Dado que el contexto actual no está autenticado, es probable que no haya forma de obtener un token de seguridad para el usuario. Por lo tanto, las únicas opciones son suplantar con credenciales. Podría ser posible construir un WindowsPrincipal con la identidad correcta llamando LogonUser (siempre que el código conoce las credenciales para el usuario de Windows). Sin embargo, no lo he intentado, así que no puedo garantizar que funcione necesariamente. –

+0

Esa es una explicación increíblemente útil, gracias.Crear un GenericPrincipal (desde mi FormsAuthenticationTicket) me permitió establecer HttpContext.Current.User. Sin embargo, todavía no puedo establecer los valores del perfil. Si uso ProfileBase.Create (Membership.GetUser(). UserName) .SetPropertyValue, no ocurre nada, ya no arroja una excepción, pero la propiedad permanece vacía. Si uso HttpContext.Current.Profile.SetPropertyValue, dice que no puedo establecer propiedades en un perfil anónimo, lo que implica que estos son diferentes objetos de perfil que de alguna manera tengo que fusionar. –

0

En primer lugar, gracias @Jeremy por compartir sus hallazgos. Me ayudaste a ir en la dirección correcta. En segundo lugar, perdón por chocar esta publicación anterior. Espero que esto ayude a alguien a conectar los puntos.

La forma finalmente conseguí este trabajo fue utilizar el siguiente método estático dentro de mi clase de perfil:

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

usted va a tener problemas con este enfoque si se habilita anonymousIdentification. En lugar de Membership.GetUser(). UserName, sugeriría usar HttpContext.Profile.UserName.

Así ...

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

Sombrero de punta: SqlProfileProvider - can you use Profile.GetProfile() in a project?

Cuestiones relacionadas