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?
-
23-09-2019 - |
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 só 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()
.
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();
}