lunes, 24 de septiembre de 2007

Inicios de Sesión

El control de acceso sobre Struts puede realizarse de varias maneras, vamos a revisar una de las mas sencillas y que no utiliza ninguna de las especificaciones propias de HTTP para su login.

Struts incluye el concepto de Interceptor, esta es una clase que realiza una acción antes de que el Action propiamente dicho se ejecute, así por ejemplo podemos agregar un Interceptor que se encargue de iniciar una sesión en caso de que esta no exista.

Los Interceptors son entonces "cajas" que envuelven a los actions y hay varios de ellos, pero de momento lo que nos interesa es crear un nuevo Interceptor para validar que nuestros usuarios esten dentro del sistema.

Para empezar vamos a crear un Action que se encarga del inicio de sesión.


public class LoginAction extends ActionSupport implements SessionAware {
private String usuario;
private String password;
private LoginDao dao;

//Getters y Setters omitidos por resumen

public String execute() {
if(!dao.userExists(usuario)) {
addActionError(getText("user.unknown"));
return INPUT;
}

if(!dao.login(usuario, password)) {
addActionError(getText("password.invalid"));
return INPUT;
}

//Una vez logeado ponemos los datos en la sesión
session.put("usuario", dao.getIdUsuario(usuario));
return SUCCESS;
}
}


El action necesita una JSP para mostrar su interfaz y un validador, supongamos que el JSP se llama login.jsp


<%@taglib prefix="s" uri="/struts-tags" %>

<s:actionerror/>
<s:form action="Login">
<s:textfield name="usuario" label="Usuario" />
<s:password name="contrasenia" label="Contraseña" />

<s:submit value="Iniciar Sesión" />
</s:form>


Una vez con ambos elementos partimos de el supuesto de que existe un action llamado Bienvenida que es donde inicia el sitio. Modificamos entonces el struts.xml pata referenciar los actions entre si.



<action name="Bienvenida.action">
<!-- No se que vaya aqui -->
</action>

<action name="Login" class="ClaseLogin">
<!-- Si el login es exitoso se envia al action de Bienvenida -->
<result type="redirect-action">Bienvenida</result>
<!-- Registramos la pagina de login -->
<result name="input">/login.jsp</result>
</action>



Una vez que tenemos estos elementos podemos ingresar a
Login.action
y revisar la pagina recien creada. Sin embargo esta funciona solamente que sea la primera que se muestre... o sea index.jsp, pero generalmente no es asi. Además, si alguna persona teclea la URL directa a un action y no ha iniciado sesión entonces entrara sin problemas. Aqui es donde entra el Interceptor, que tomara cualquier petición al sistema y se asegurara de que el login exista. La clase Interceptor es mas o menos algo asi:


public class LoginInterceptor extends AbstractInterceptor {
private static String HTTP_REQUEST ="com.opensymphony.xwork2.dispatcher.HttpServletRequest";

public String intercept(ActionInvocation ai) {
ActionContext ac = ai.getInvocationContext();
HttpServletRequest request = ac.get(HTTP_REQUEST);
HttpSession session = request.getSession();

String val = session.getAttribute("usuario");
if(val == null || val.trim().length() = 0) {
//Si se esta logeando puede entrar al sitio
if(ai.getAction().getClass() == LoginAction.class)
return ai.invoke();

return "login";
}

//Si llega aqui entonces presuponemos que ya hay un login valido
return ai.invoke();
}
}


Solamente resta registrar el Interceptor dentro del mismo struts.xml para que este cargue en cualquier pagina solicitada.


<!-- Colocamos esto despues de abrir la etiqueta package -->
<interceptors>
<!-- Registramos el nuevo interceptor -->
<interceptor name="loger" class="LoginAction" />

<!-- Creamos una nueva pila de interceptors para adecuarla a nuestro ejemplo -->
<interceptor-stack name="include_session">
<!-- Agregamos un interceptor que crea la session para evitar que esta este vacia -->
<interceptor-ref name="createSession" />
<!-- Posteriormente nuestro recien creado interceptor -->
<interceptor-ref name="loger" />
<!-- Y todos los interceptors que van por default -->
<interceptor-ref name="completeStack" />
</interceptor-stack>
</interceptors>

<!-- Sobreescribimos el stack de interceptors por el que acabamos de definir -->
<default-interceptor-ref name="include_session" />

<!-- Finalmente creamos un GlobalResult para interceptar la falta de login al sitio -->
<global-results>
<result name="login">/login.jsp</result>
</global-results>

No hay comentarios: