domingo, junio 24, 2007

Como configurar un WebSite con autenticacion 'Forms' y dos paginas de Login.

Bueno, lo primero saludar a mis amigos Jesús, David y David ;) que me han dejado un sitio en su blog para poder publicar cositas interesantes.

Vamos allá. Lo que necesitamos esta vez es tener un web site al que puedan acceder dos tipos de usuarios distintos a dos partes del site diferenciadas pero dentro de la misma aplicacion. Imaginemos un tipo de usuario alumno y un tipo de usuario centro. Los alumnos se pueden conectar para ver sus notas y los centros se pueden conectar para ver los alumnos que se han presentado a cada examen y las notas que han sacado de tal manera que compaten base de datos. Ahora nos preguntaremos, para que queremos un web site con dos accesos diferentes?, será mejor hacer dos web sites no? uno para cada tipo de usuario, con sus paginas y sus rollos no? pues si! pero..., jeje, el cliente lo quiere así y así lo tenemos que hacer.

La solucion que se nos ocurre a bote pronto es organizar el site en dos partes, una para alumnos y otra para centros. A nivel de root crear un web.config con la configuracion global y luego una carpeta para cada una de las partes con su propio web.config .
Hasta aqui todo bien, ponemos en el root el web.config y declaramos que la autenticacion va a ser del tipo 'Forms' y que redireccione a una pagina de login que pondremos en la raiz del site:

<authentication mode="Forms">
<forms name=".cookiename" timeout="20" protection="All" loginurl="login.aspx">
</authentication>

Ahora si intentamos poner la misma tag en el web.config de la carpeta alumnos para que redireccione a loginalumnos.aspx tachan!!!! application error:
It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS.
Esto es debido a que solo se puede declarar el tag authentication a nivel de aplicacion (en el web.config del root) y una sola vez.
Vaya por dios, entonces? como hacemos? si queremos tener dos paginas de login!.

Bueno pues tendremos que hacerlo de alguna manera que nos permita redireccionar desde la pagina login del root a cada una de las paginas de login dependiendo a donde queramos acceder. Una vez authenticados, crearemos un rol para el usuario (si es alumno 'Alumno' y si es centro 'Centro') y solo dejaremos acceder a las páginas dependiendo de este rol.
Para hacer esto, unicamente tendremos que agregar el tag de autorizacion a cada uno de los web.config:
Para la carpeta de alumnos:
<authorization>
<allow roles="Alumno">
<deny users="*">
</authorization>
Para la carpeta de centros:
<authorization>
<allow roles="Centro">
<deny users="*">
</authorization>

Además, para completar el web.config tendremos que añadir las tag "location path=" para todas las paginas que queramos que puedan acceder tanto usuarios registrados como anónimos (en este caso para la de login y para la de help). Si no ponemos esto, no nos dejaría entrar en la pagina de login porque no tenemos el rol correspondiente.

<location path="Login.aspx">
<system.web>
<authorization>
<allow users="*"/>
<allow users="?"/>
</authorization>
</system.web>
</location>
<location path="Help.aspx">
<system.web>
<authorization>
<allow users="?"/>
</authorization>
</system.web>
</location>

Ahora en la pagina de login,depues de comprobar que el usuario y pass son correctos, tendremos que añadir el rol:

public void CreateNewMemberTicket(string username, Role userRole, bool persistent)
{
//get user roles
string role = GetRoleName(userRole);
// Create a new ticket used for authentication
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
username, // Username associated with ticket
DateTime.Now, // Date/time issued
DateTime.Now.AddMinutes(20), // Date/time to expire
persistent, // "false" for a non persistent user cookie
role, // User-data, in this case the roles
FormsAuthentication.FormsCookiePath);// Path cookie valid for
// Encrypt the cookie using the machine key for secure transport
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, // Name of auth cookie
hash); // Hashed ticket
// Set the cookie's expiration time to the tickets expiration time
if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
// Add the cookie to the list for outgoing response
Response.Cookies.Add(cookie);
}

Con esto conseguimos añadir a la cookie de authenticacion el rol del usuario. Ya solo nos queda crearnos el objeto GenericPrincipal para que el usuario que está logeado pueda ver la pagina que solicita al servidor, es decir, despues de logearse si va a la pagina alumnohome.aspx tendremos que asegurarnos que el rol que tiene el usuario en ese momento es el de 'Alumno' y sino redireccionarlo a la pagina de login.

Esto lo hacemos en el metodo Application_AuthenticateRequest de la Global.asax (si no la tenemos la añadimos al website)

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity is FormsIdentity)
{
FormsIdentity id =(FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;

// Get the stored user-data, in this case, the roles
string userData = ticket.UserData;
HttpContext.Current.User = new GenericPrincipal(id,roles);
}
}
}
}

En la pagina de login del root debemos tambien redirigir a la de login de alumno o centro:

protected override void OnInit(EventArgs eventArgs)
{

string returnvalue = Request.QueryString.Get("ReturnUrl").ToLower();
if(returnvalue != null)
{

if(returnvalue.IndexOf("/alumnos/") != -1)
{
Server.Transfer("~/alumnos/Login.aspx");

}
else if (returnvalue.IndexOf("/centros/") != -1)
{
Server.Transfer("~/centros/Login.aspx")
}
}

base.OnInit(eventArgs);
}


HTH jeje,

Un saludo desde tierras del norte! Cuidaros ;)

1 comentario:

MD dijo...

Hola q tal

sabes me intereso este postdeautenticacion lo q pasa esq estoy haciendo una aplicacion web en c# y me preguntaba si mepodrias ayudar xq hayuna parte qno le entendi
bueno saludos