Quando utilizamos FormsAuthentication para proteger uma determina página ou diretório, há um comportamento que talvez não agrade a maioria das pessoas. Suponhamos que você faça o login digitando o seu nome de usuário e senha. Ao validar esse usuário em algum repositório, o ASP.NET automaticamente redireciona o usuário para a página/diretório que ele tentou acessar inicialmente.
A partir daí, se você utilizar roles para restringir o acesso à alguma página/diretório dentro da aplicação e o usuário não esteja dentro dela, ele será redirecionado – novamente – para a página de login. Talvez isso não seja o ideal, já que o mais coerente seria redirecionar o usuário para uma página que contenha uma mensagem mais amigável e próxima ao que realmente aconteceu, algo como: “Você não tem permissão para acessar o recurso solicitado. Contate o Administrator.”.
Quando utilizamos a UrlAuthorization (que já é o padrão), a cada requisição ela verifica se o usuário que acessa uma determinada página, possui a permissão para isso. Caso a configuração no arquivo Web.config diz que, para acessar aquela página, é necessário que o usuário esteja na role de “Administradores”, e ele por sua vez não estiver, o UrlAuthorization define a propriedade StatusCode da resposta do HTTP para 401 (que significa “Acesso Negado”). O FormsAuthentication (mais precisamente, o FormsAuthenticationModule) se vincula ao evento EndRequest, e dentro dele analisa se a propriedade StatusCode foi definida como 401. Caso tenha sido, o FormsAuthenticationModule redireciona o usuário para a página de login, trocando o StatusCode para 302 (“Redirecionar”).
Para mudar este comportamento, podemos criar um módulo e nos vincularmos ao evento EndRequest. Dentro deste evento, podemos analisar se a propriedade StatusCode foi definida como 401, e se estiver, redirecionar para uma página que informa exibe a mensagem correta ao invés da página de login, melhorando assim a navegabilidade da aplicação. O módulo é extremamente simples, assim como podemos notar abaixo:
public class AccessDeniedModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.EndRequest += new EventHandler(context_EndRequest);
}
private void context_EndRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
if (app.Response.StatusCode == 401 && app.User.Identity.IsAuthenticated)
{
app.Response.Redirect(“~/AreaRestrita/AcessoNegado.aspx”);
}
}
public void Dispose() { }
}
Como já sabemos, para que um módulo funcione, precisamos acoplá-lo na execução do ASP.NET, e fazemos isso através do elemento <httpModules />. Mas este módulo deve ter um cuidado especial para que funcione adequadamente. Já existem diversos módulos em execução pelo ASP.NET, e um deles é justamente o FormsAuthenticationModule. Se simplesmente adicionarmos o módulo que criamos na coleção de módulos da aplicação, o StatusCode vai chegar sempre como 302, pois a requisição primeiramente passará pelo módulo FormsAuthenticationModule, que como vimos acima, faz essa mudança. Com isso, a nossa condicional sempre irá falhar, fazendo com que o usuário seja redirecionado para a página de login. A dica aqui é ir até o arquivo Web.config que está em nível de servidor (%windir%Microsoft .NETFrameworkVERSÃOCONFIG), copiar a coleção de módulos e colar no arquivo Web.config da aplicação, como podemos ver abaixo:
<httpModules>
<clear />
<add name=”ScriptModule”
type=”System.Web.Handlers.ScriptModule, System.Web.Extensions”/>
<add name=”OutputCache”
type=”System.Web.Caching.OutputCacheModule”/>
<add name=”Session”
type=”System.Web.SessionState.SessionStateModule”/>
<add name=”AccessDeniedModule”
type=”AccessDeniedModule”/>
<add name=”FormsAuthentication”
type=”System.Web.Security.FormsAuthenticationModule”/>
<add name=”RoleManager”
type=”System.Web.Security.RoleManagerModule”/>
<add name=”UrlAuthorization”
type=”System.Web.Security.UrlAuthorizationModule”/>
<add name=”AnonymousIdentification”
type=”System.Web.Security.AnonymousIdentificationModule”/>
<add name=”Profile”
type=”System.Web.Profile.ProfileModule”/>
</httpModules>
Depois de colocar os módulos no arquivo Web.config da aplicação, precisamos colocar o elemento <clear /> para que não duplique a execução dos módulos. E para finalizar, o módulo que criamos deverá ser colocado antes do módulo do FormsAuthentication para que funcione como o esperado. Aproveitando a oportunidade, é importante que você deixe somente os módulos que a sua aplicação realmente utiliza, ganhando alguma performance, já que evitará passar por passos desnecessários. Para maiores detalhes sobre isso, consulte este artigo.
Esse módulo é bastante útil.
Valeu.
Boas Fabio,
Apesar de isso funcionar, não é uma forma elegante. Com a técnica que você sugere, o processo acontece da seguinte forma:
PaginaRestrita.aspx (401) -> Login.aspx (302) -> NotAuthorized.aspx (302)
No exemplo que fiz:
PaginaRestrita.aspx (401) -> NotAuthorized.aspx (302)
Além disso, código de infraestrutura não deve estar "jogado" pela aplicação. Utilizar módulos como foi o caso aqui, fica muito mais simples para gerenciar e, principalmente, para reutilizar em diversas outras aplicações.
Ê mania que desenvolvedor .NET tem que colocar tudo na interface.
Mto bom mesmo. Mtas matérias e conceitos interessantes que estou aprendendo aqui.
Valeu!
Israel boa tarde,
Existe algum forma de bloquear o acesso a pasta /admin/default.aspx ? tipo tem um site com gerenciador e queria liberar o acesso a essa pasta só para algumas pessoas pq se deixar aberto fico com medo de os hackers tentar colocar um robô para derrubar o servidor ou descobrir até a senha. existe alguma maneira ?
Boas Marcos,
Não sei se entendi direito a sua dúvida, mas o FormsAuthentication já não protegê? Você só pode acessar depois de autenticado.
Awesome post ! Thank you for, commenting on this blog page mate. I will message you soon! I didn’t know that.