FormsAuthentication.SignOut() não desconecta o usuário
-
03-07-2019 - |
Pergunta
Bati minha cabeça contra isso um pouco demais.Como evito que um usuário navegue nas páginas de um site depois de ter sido desconectado usando FormsAuthentication.SignOut?Eu esperaria que isso acontecesse:
FormsAuthentication.SignOut();
Session.Abandon();
FormsAuthentication.RedirectToLoginPage();
Mas isso não acontece.Se eu digitar um URL diretamente, ainda poderei navegar até a página.Faz algum tempo que não uso a segurança do tipo roll-your-own, então esqueço por que isso não funciona.
Solução
Os usuários ainda podem navegar no seu site porque os cookies não são limpos quando você liga FormsAuthentication.SignOut()
E eles são autenticados em cada nova solicitação. Na MS A documentação é diz que o cookie será liberado, mas não, bug? É exatamente o mesmo com Session.Abandon()
, Cookie ainda está lá.
Você deve alterar seu código para isso:
FormsAuthentication.SignOut();
Session.Abandon();
// clear authentication cookie
HttpCookie cookie1 = new HttpCookie(FormsAuthentication.FormsCookieName, "");
cookie1.Expires = DateTime.Now.AddYears(-1);
Response.Cookies.Add(cookie1);
// clear session cookie (not necessary for your current problem but i would recommend you do it anyway)
SessionStateSection sessionStateSection = (SessionStateSection)WebConfigurationManager.GetSection("system.web/sessionState");
HttpCookie cookie2 = new HttpCookie(sessionStateSection.CookieName, "");
cookie2.Expires = DateTime.Now.AddYears(-1);
Response.Cookies.Add(cookie2);
FormsAuthentication.RedirectToLoginPage();
HttpCookie
está no System.Web
espaço para nome. Referência do MSDN.
Outras dicas
Parece -me que você não tem sua seção de autorização Web.Config configurada corretamente dentro. Veja abaixo um exemplo.
<authentication mode="Forms">
<forms name="MyCookie" loginUrl="Login.aspx" protection="All" timeout="90" slidingExpiration="true"></forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
Usando duas das postagens acima por X64igor e Phil Haselden resolveu o seguinte:
1. X64igor deu o exemplo para fazer o logout:
Você primeiro precisa Limpe o cookie de autenticação e o cookie de sessão Ao repassar os cookies vazios na resposta ao logout.
public ActionResult LogOff() { FormsAuthentication.SignOut(); Session.Clear(); // This may not be needed -- but can't hurt Session.Abandon(); // Clear authentication cookie HttpCookie rFormsCookie = new HttpCookie( FormsAuthentication.FormsCookieName, "" ); rFormsCookie.Expires = DateTime.Now.AddYears( -1 ); Response.Cookies.Add( rFormsCookie ); // Clear session cookie HttpCookie rSessionCookie = new HttpCookie( "ASP.NET_SessionId", "" ); rSessionCookie.Expires = DateTime.Now.AddYears( -1 ); Response.Cookies.Add( rSessionCookie );
2. Phil Haselden deu o exemplo acima de como evitar o cache após o logout:
Você precisa Invalidar o cache no lado do cliente através da resposta.
// Invalidate the Cache on the Client Side Response.Cache.SetCacheability( HttpCacheability.NoCache ); Response.Cache.SetNoStore(); // Redirect to the Home Page (that should be intercepted and redirected to the Login Page first) return RedirectToAction( "Index", "Home" ); }
A chave aqui é que você diz "se eu digitar um URL diretamente ...".
Por padrão, em Forms Autenticação, as páginas do navegador armazenam em cache para o usuário. Portanto, selecionar um URL diretamente no suspensão da caixa de endereço dos navegadores ou digitando -o pode obter a página do cache do navegador e nunca mais voltar ao servidor para verificar a autenticação/autorização. A solução para isso é impedir o cache do lado do cliente no evento Page_load de cada página ou no Onload () da sua página base:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Você também pode gostar de ligar:
Response.Cache.SetNoStore();
Eu já lutei com isso antes também.
Aqui está uma analogia para o que parece estar acontecendo...Um novo visitante, Joe, chega ao site e faz login através da página de login usando FormsAuthentication.ASP.NET gera uma nova identidade para Joe e lhe dá um cookie.Esse biscoito é como a chave da casa e, desde que Joe retorne com essa chave, ele poderá abrir a fechadura.Cada visitante recebe uma nova chave e um novo cadeado para usar.
Quando FormsAuthentication.SignOut()
é chamado, o sistema diz a Joe para perder a chave.Normalmente isso funciona, já que Joe não tem mais a chave, ele não consegue entrar.
No entanto, se Joe voltar, e faz se tiver aquela chave perdida, ele poderá entrar novamente!
Pelo que sei, não há como dizer ao ASP.NET para alterar a fechadura da porta!
A maneira de conviver com isso é lembrar o nome de Joe em uma variável de sessão.Quando ele sai, eu abandono a Sessão e não tenho mais o nome dele.Posteriormente, para verificar se ele tem permissão para entrar, simplesmente comparo seu Identity.Name com o que a sessão atual possui e, se não corresponderem, ele não é um visitante válido.
Resumindo, para um site, NÃO confie em User.Identity.IsAuthenticated
sem também verificar suas variáveis de sessão!
Isso funciona para mim
public virtual ActionResult LogOff()
{
FormsAuthentication.SignOut();
foreach (var cookie in Request.Cookies.AllKeys)
{
Request.Cookies.Remove(cookie);
}
foreach (var cookie in Response.Cookies.AllKeys)
{
Response.Cookies.Remove(cookie);
}
return RedirectToAction(MVC.Home.Index());
}
Depois de muita pesquisa, finalmente funcionou para mim. Espero que ajude.
public ActionResult LogOff()
{
AuthenticationManager.SignOut();
HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
return RedirectToAction("Index", "Home");
}
<li class="page-scroll">@Html.ActionLink("Log off", "LogOff", "Account")</li>
O código que você postou parece remover corretamente o token de autenticação de formulários, por isso é possível que as pastas/páginas em questão não estejam realmente protegidas.
Você confirmou que as páginas não podem ser acessadas antes que um login ocorra?
Você pode postar as configurações do Web.config e o código de login que está usando?
Escrevi uma classe base para todas as minhas páginas e cheguei ao mesmo problema. Eu tinha código como o seguinte e não funcionou. Ao rastrear, o controle passa da instrução redirectTologInpage () para a próxima linha sem ser redirecionada.
if (_requiresAuthentication)
{
if (!User.Identity.IsAuthenticated)
FormsAuthentication.RedirectToLoginPage();
// check authorization for restricted pages only
if (_isRestrictedPage) AuthorizePageAndButtons();
}
Eu descobri que existem duas soluções. Para modificar o formSAuthentication.RedirectTologInPage (); ser
if (!User.Identity.IsAuthenticated)
Response.Redirect(FormsAuthentication.LoginUrl);
Ou para modificar o web.config, adicionando
<authorization>
<deny users="?" />
</authorization>
No segundo caso, durante o rastreamento, o controle não atingiu a página solicitada. Foi redirecionado imediatamente para o URL de login antes de atingir o ponto de interrupção. Portanto, o método Signout () não é o problema, o método de redirecionamento é o único.
Espero que isso possa ajudar alguém
Cumprimentos
Acabei de experimentar algumas das sugestões aqui e, embora pude usar o botão Back do navegador, quando cliquei em uma seleção de menu, o token [Authorize] para que o [ActionResult] me enviou de volta à tela de login.
Aqui está o meu código de logout:
FormsAuthentication.SignOut();
Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
HttpCookie cookie = HttpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null)
{
cookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(cookie);
}
Embora a função traseira no navegador tenha me levado de volta e exibisse o menu seguro (ainda estou trabalhando nisso), não consegui fazer nada que estivesse protegido no aplicativo.
Espero que isto ajude
Eu tentei a maioria das respostas neste tópico, sem sorte. Acabou com isso:
protected void btnLogout_Click(object sender, EventArgs e)
{
FormsAuthentication.Initialize();
var fat = new FormsAuthenticationTicket(1, "", DateTime.Now, DateTime.Now.AddMinutes(-30), false, string.Empty, FormsAuthentication.FormsCookiePath);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(fat)));
FormsAuthentication.RedirectToLoginPage();
}
Encontrei aqui: http://forums.asp.net/t/1306526.aspx/1
Esta resposta é tecnicamente idêntica a Khosro.pakmanesh. Estou postando para esclarecer como a resposta dele difere de outras respostas neste tópico e no qual o caso de uso pode ser usado.
Em geral para limpar uma sessão do usuário, fazendo
HttpContext.Session.Abandon();
FormsAuthentication.SignOut();
irá efetivamente fazer logon o usuário. No entanto, se no mesmo pedido, você precisará verificar Request.isAuthenticated
(Como pode acontecer com frequência em um filtro de autorização, por exemplo), então você encontrará que
Request.isAuthenticated == true
até _ depois de você fez HttpContext.Session.Abandon()
e FormsAuthentication.SignOut()
.
A única coisa que funcionou foi fazer
AuthenticationManager.SignOut();
HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
Isso efetivamente define Request.isAuthenticated = false
.
Isso começou a acontecer comigo quando eu defini o Autenticação> Forms> Propriedade do caminho dentro Web.config
. Removendo que corrigiu o problema e um simples FormsAuthentication.SignOut();
novamente removeu o biscoito.
Pode ser que você esteja efetuando login a partir de um subdomínio (sub1.domain.com) e depois tentando fazer logout de um subdomínio diferente (www.domain.com).
Acabei de ter o mesmo problema, onde o Signout () aparentemente não conseguiu remover corretamente o ticket. Mas apenas em um caso específico, onde alguma outra lógica causou um redirecionamento. Depois de remover esse segundo redirecionamento (substituí -lo por uma mensagem de erro), o problema desapareceu.
O problema deve ter sido que a página foi redirecionada na hora errada, portanto, não desencadeando a autenticação.
Estou tendo um problema semelhante agora e acredito que o problema no meu caso e o pôster original é por causa do redirecionamento. Por padrão, uma resposta.Direct causa uma exceção que imediatamente borbulha até que seja capturada e o redirecionamento seja executado imediatamente, acho que isso está impedindo que a coleção de cookies modificada seja passada para o cliente. Se você modificar seu código para usar:
Response.Redirect("url", false);
Isso impede a exceção e parece permitir que o cookie seja enviado corretamente de volta ao cliente.
Basta tentar enviar uma variável de sessão ao pressionar o login. E na página de boas -vindas, verifique se a sessão está vazia assim na página Carregar ou no evento init:
if(Session["UserID"] == null || Session["UserID"] == "")
{
Response.Redirect("Login.aspx");
}
Para mim, a seguinte abordagem funciona. Eu acho que se houver algum erro após a declaração "FormSauthentication.signout ()", Singout não funciona.
public ActionResult SignOut()
{
if (Request.IsAuthenticated)
{
FormsAuthentication.SignOut();
return Redirect("~/");
}
return View();
}
Você está testando/vendo esse comportamento usando o IE? É possível que o IE esteja servindo essas páginas do cache. É notoriamente difícil fazer com que o IE funcione seu cache e, em muitas ocasiões, mesmo depois de fazer o logout, digitar o URL de uma das páginas "garantidas" mostraria o conteúdo em cache de antes.
(Eu já vi esse comportamento mesmo quando você registra como um usuário diferente, e o IE mostra o bar "Welcome" no topo da sua página, com o nome de usuário do antigo usuário. Atualmente, geralmente um recarregamento o atualizará, mas se for persistente , ainda pode ser um problema de cache.)
Fazendo session.abandon () e destruir o cookie funciona muito bem. Estou usando o MVC3 e parece que o problema ocorre se você for a uma página protegida, logo sair e passar pelo histórico do seu navegador. Não é grande coisa, mas ainda é irritante.
Tentar passar por links no meu aplicativo da web funciona da maneira certa.
Definê -lo para não fazer o cache do navegador pode ser o caminho a seguir.
Para o MVC, isso funciona para mim:
public ActionResult LogOff()
{
FormsAuthentication.SignOut();
return Redirect(FormsAuthentication.GetRedirectUrl(User.Identity.Name, true));
}
Eu queria adicionar algumas informações para ajudar a entender o problema. A autenticação de formulários permite armazenar dados do usuário em um cookie ou na sequência de consulta do URL. O método que seu site suporta pode ser configurado no arquivo web.config.
O método de inscrição remove as informações do ingresso de autenticação de formulários do cookie ou do URL Se Cookiessupported é falso.
Ao mesmo tempo, eles dizem:
Um dos valores HttpCookiemode que indica se o aplicativo está configurado para a autenticação de formulários de cozinheiro. o O padrão é usado oPROFILE.
Por fim, em relação ao UsoEviceProfile, eles dizem:
Se a propriedade Cookiemode for definida como UseviceProfile, o A propriedade CookiessUported retornará verdadeira se o navegador para o A solicitação atual suporta cookies e redirecionando com cookies; Caso contrário, a propriedade Cookiessupport retornará falsa.
Reunindo tudo isso tudo, dependendo do navegador do usuário, a configuração padrão pode resultar em ser apoiado verdadeiro, o que significa que o método de inscrição não limpa o bilhete do cookie. Isso parece contra-intuitivo e não sei por que funciona dessa maneira-eu esperaria que a inscrição assinasse o usuário em nenhuma circunstância.
Uma maneira de fazer a inscrição funcionar por si só é alterar o modo de cookie para "usecookies" (ou seja, cookies) no arquivo web.config:
<authentication mode="Forms">
<forms loginUrl="~/Account/SignIn" cookieless="UseCookies"/>
</authentication>
De acordo com meus testes, fazer isso faz com que a inscrição funcione por si só, com o custo do seu site, agora exigindo que os cookies funcionem corretamente.
Esteja ciente de que wif recusa Para dizer ao navegador para limpar os cookies se a mensagem WSIGNOUTCLEANUP do STS não corresponde ao URL com o nome do aplicativo do IIS, e quero dizer MAIÚSCULAS E MINÚSCULAS. Wif responde com o verde verde, mas vai não Envie o comando para excluir cookies para o navegador.
Portanto, você precisa prestar atenção à sensibilidade do caso dos seus URLs.
Por exemplo, o ThinkTecture Identity Server salva os URLs dos RPs visitantes em um cookie, mas faz com que todos eles sejam minúsculos. WIF receberá a mensagem WSIGNOUTCLEANUP em minúsculas e a comparará com o nome do aplicativo no IIS. Se não corresponder, não exclui cookies, mas relatará ok para o navegador. Portanto, para este servidor de identidade, eu precisava escrever todos os URLs no web.config e todos os nomes de aplicativos no IIS em minúsculos, a fim de evitar esses problemas.
Além disso, não se esqueça de permitir biscoitos de terceiros no navegador se você tiver os aplicativos fora do subdomínio do STS, caso contrário, o navegador não excluirá os cookies, mesmo que WIF lhe diga.