Usando a associação e o perfil do ASP .NET com o MVC, como posso criar um usuário e defini -lo como httpcontext.current.user?

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

Pergunta

Eu implementei um objeto de perfil personalizado no código, conforme descrito por Joel aqui:

Como atribuir valores de perfil?

No entanto, não consigo fazer funcionar quando estou criando um novo usuário. Quando eu faço isso:

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

O usuário é criado e adicionado a uma função no banco de dados, mas HttpContext.Current.User ainda está vazio e Membership.GetUser() Retorna NULL, então este (do código de Joel) não funciona:

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

AccountProfile.CurrentUser.FullName = "Snoopy";

Eu tentei ligar Membership.GetUser(userName) e definir as propriedades do perfil dessa maneira, mas as propriedades definidas permanecem vazias e chamando AccountProfile.CurrentUser(userName).Save() Não coloca nada no banco de dados. Eu também tentei indicar que o usuário é válido e conectado, ligando Membership.ValidateUser, FormsAuthentication.SetAuthCookie, etc., mas o usuário atual ainda é nulo ou anônimo (dependendo do estado dos meus cookies do navegador).

Resolvido (editado ainda mais, veja abaixo): Com base na explicação de Franci Penov e mais algumas experimentações, descobri o problema. O código de Joel e as variações que tentei funcionarão apenas com um perfil existente. Se não houver perfil, ProfileBase.Create(userName) retornará um novo objeto vazio toda vez que for chamado; Você pode definir propriedades, mas elas não "grudam" porque uma nova instância é retornada toda vez que você acessa. Contexto HttpContext.Current.User para um novo GenericPrincipal vai Dê a você um objeto de usuário, mas não um objeto de perfil, e ProfileBase.Create(userName) e HttpContext.Current.Profile ainda apontará para objetos novos e vazios.

Se você deseja criar um perfil para um usuário recém-criado na mesma solicitação, você precisa ligar HttpContext.Current.Profile.Initialize(userName, true). Você pode preencher o perfil inicializado e salvá -lo, e ele estará acessível em solicitações futuras pelo nome, para que o código de Joel funcione. Eu sou usando HttpContext.Current.Profile Internamente, quando preciso criar/acessar o perfil imediatamente após a criação. Em quaisquer outros pedidos, eu uso ProfileBase.Create(userName), e eu expus apenas essa versão como pública.

Observe que Franci está correto: se você estiver disposto a criar o usuário (e as funções) e defini-lo como autenticado na primeira viagem de ida e volta e peça ao usuário que faça login, você poderá acessar o perfil muito mais simplesmente simplesmente simplesmente via código de Joel na solicitação subsequente. O que me jogou é que as funções são imediatamente acessíveis na criação do usuário sem nenhuma inicialização, mas o perfil não é.

Meu novo código da conta:

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

Criação de novos usuários:

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

Acesso subsequente:

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

Além disso, obrigado a Franci por explicar o ciclo de vida da autenticação - estou chamando o formsAuthentication.

Revisado: Eu sou um idiota. A explicação acima funciona no caso estreito, mas não resolve o problema principal: chamar o CurrentUser retorna uma nova instância do objeto a cada vez, seja um perfil existente ou não. Por ser definido como uma propriedade, eu não estava pensando sobre isso e escrevi:

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

que (é claro) não funciona. Deveria ser:

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

É minha culpa por negligenciar completamente esse ponto básico, mas acho que declarar o CurrentUser como uma propriedade implica que é um objeto que pode ser manipulado. Em vez disso, deve ser declarado como GetCurrentUser().

Foi útil?

Solução

Criar um usuário apenas adiciona à lista de usuários. No entanto, isso não autentica ou autoriza o novo usuário para a solicitação atual. Você também precisa autenticar o usuário no contexto de solicitação atual ou para solicitações subsequentes.

Membership.ValidateUser Validará apenas as credenciais, mas não está autenticando o usuário para as solicitações atuais ou subsequentes. FormsAuthentication.SetAuthCookie Definirá o ticket de autenticação no fluxo de resposta, para que a próxima solicitação seja autenticada, mas não afeta o estado da solicitação atual.

A maneira mais fácil de autenticar o usuário seria ligar FormsAuthentication.RedirectFromLoginPage (Supondo que você esteja usando a autenticação de formulários em seu aplicativo). No entanto, este realmente causaria uma nova solicitação HTTP, que autenticará o usuário.

Como alternativa, se você precisar continuar sua lógica para processar a solicitação atual, mas deseja que o usuário seja autenticado, você pode criar um GenericPrincipal, atribua a identidade do novo usuário e defina o HttpContext.User para esse diretor.

Outras dicas

Assumindo que este é 2013 (já que não há nenhuma versão note) ... Você pode ter uma caixa de diálogo aberta a partir de outra caixa de diálogo.Que fecha automaticamente o primeiro (tecnicamente, o que acredito que ele faz, na verdade, é chamar a página do aplicativo em questão dentro do quadro da caixa de diálogo modal original; isso explicaria por que você não recebe comportamentos como postbacks automáticosnessa transição).

Se você realmente realmente disparar no fechamento da primeira caixa, você deve poder chamá-lo de sua função de retorno de chamada.Veja a assinatura aqui:

sp.ui.modaldialog.commonmodaldopen (URL, opções, chamada de retorno, null);

O retorno de chamada requer 2 argumentos (acredito que os nomes aconselhados pelo SP para aqueles são "resultado" e "valor"), e você pode usá-los para determinar como a caixa de diálogo modal foi fechada.Muitas vezes uso esse retorno de chamada para causar um postback, mas você pode usá-lo para qualquer coisa Javascript, realmente.

Primeiro de tudo, obrigado @Jeremy por compartilhar suas descobertas. Você me ajudou a seguir na direção certa. Em segundo lugar, desculpe -se por esbarrar neste antigo post. Espero que isso ajude alguém a conectar os pontos.

A maneira como finalmente consegui isso funcionando foi usar o seguinte método estático dentro da minha aula 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();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top