Implementación de Interceptores Personalizados para Control de Acceso en Struts2

En el desarrolol de aplicaciones web con Struts2, los interceptores son herramientas fundamentales para separar la lógica de negocio de las tareas transversales como la seguridad, el registro de logs o la validación. Un caso de uso común es la restricción de acceso a ciertas áreas de la aplicación basándose en el estado de la sesión del usuario.

Definición del Modelo de Datos

Para gestionar la información del usuario, definimos una clase POJO sencilla que represente las credenciales en el sistema.

package com.sistema.model;

public class CuentaUsuario {
    private String nombre;
    private String clave;

    // Getters y Setters
    public String getNombre() { return nombre; }
    public void setNombre(String nombre) { this.nombre = nombre; }
    public String getClave() { return clave; }
    public void setClave(String clave) { this.clave = clave; }
}

Lógica de Autenticación

Es una buena práctica separar la validación de credenciales en una capa de servicio independiente.

package com.sistema.service;

import com.sistema.model.CuentaUsuario;

public class ServicioAuth {
    public boolean validarAcceso(CuentaUsuario usuario) {
        // Validación estática para el ejemplo
        return "admin".equals(usuario.getNombre()) && "secret123".equals(usuario.getClave());
    }
}

Creación del Interceptor de Seguridad

El interceptor se encarga de examinar la sesión antes de permitir que la petición llegue al Action solicitado. Si el usuario no está presente en la sesión, se detiene el flujo y se redirige a la página de error o inicio de sesión.

package com.sistema.interceptor;

import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
import org.apache.struts2.ServletActionContext;

public class AuthInterceptor implements Interceptor {

    @Override
    public void init() { }

    @Override
    public void destroy() { }

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        Map<String, Object> session = ActionContext.getContext().getSession();
        Object usuarioActivo = session.get("sesionUsuario");

        if (usuarioActivo == null) {
            ServletActionContext.getRequest().setAttribute("mensajeError", "Acceso denegado. Por favor, identifíquese.");
            return "login_requerido";
        }

        // Continúa la ejecución hacia el Action o el siguiente interceptor
        return invocation.invoke();
    }
}

Implementación del Action de Control de Acceso

Este Action gestiona el proceso de login. Si las credenciales son correctas, almacena el objeto en la sesión HTTP.

package com.sistema.action;

import java.util.Map;
import com.sistema.model.CuentaUsuario;
import com.sistema.service.ServicioAuth;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport {
    private CuentaUsuario usuario;
    private String errorMsg;
    private ServicioAuth servicio = new ServicioAuth();

    @Override
    public String execute() {
        if (servicio.validarAcceso(usuario)) {
            Map<String, Object> session = ActionContext.getContext().getSession();
            session.put("sesionUsuario", usuario);
            return SUCCESS;
        } else {
            this.errorMsg = "Credenciales inválidas.";
            return ERROR;
        }
    }

    // Getters y Setters necesarios para Struts2
    public CuentaUsuario getUsuario() { return usuario; }
    public void setUsuario(CuentaUsuario usuario) { this.usuario = usuario; }
    public String getErrorMsg() { return errorMsg; }
}

Configuración en struts.xml

La configuración es clave para aplicar el interceptor de forma selectiva. Debemos definir un interceptor-stack que incluya nuestro interceptor personalizado junto con los predeterminados de Struts2.

<?xml version="1.0" encoding="UTF-8" ?>


<struts>
    <package name="seguro" extends="struts-default" namespace="/">
        
        <interceptors>
            <interceptor name="controlAcceso" class="com.sistema.interceptor.AuthInterceptor"/>
            <interceptor-stack name="stackSeguridad">
                <interceptor-ref name="controlAcceso"/>
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>
        </interceptors>

        <!-- Aplicar stack de seguridad por defecto a todo el paquete -->
        <default-interceptor-ref name="stackSeguridad"/>

        <global-results>
            <result name="login_requerido">/vistas/error_acceso.jsp</result>
        </global-results>

        <!-- Action protegido -->
        <action name="panelControl" class="com.sistema.action.AdminAction">
            <result name="success">/vistas/dashboard.jsp</result>
        </action>

        <!-- El login debe excluir el interceptor de seguridad para permitir el acceso inicial -->
        <action name="procesarLogin" class="com.sistema.action.LoginAction">
            <result name="success">/vistas/bienvenido.jsp</result>
            <result name="error">/vistas/login.jsp</result>
            <interceptor-ref name="defaultStack"/>
        </action>

    </package>
</struts>

Vistas de Usuario (JSP)

En el archivo login.jsp, capturamos los datos vinculándolos al objeto usuario definido en el Action.

<form action="procesarLogin" method="post">
    Usuario: <input type="text" name="usuario.nombre" />
    Clave: <input type="password" name="usuario.clave" />
    <button type="submit">Ingresar</button>
</form>

Para mostrar el nombre del usuario autenticado en la página de éxito:

<p>Bienvenido: ${sessionScope.sesionUsuario.nombre}</p>

Etiquetas: struts2 Java EE Interceptors Web Security MVC

Publicado el 6-21 03:08