martes, 16 de octubre de 2012


Arquitectura GSON
 

GSON es una pequeña biblioteca de código abierto para el lenguaje java que nos permite convertir una clase java en un String con formato JSON y viceversa, mediante la serialización y deserialización entre objetos Java y su representación en notación JSON, simplemente invocando los métodos toJson() o fromJson().
Es útil si hacemos una aplicación web con java en el lado del servidor y usamos el formato JSON para enviar y recibir datos al navegador, ya que permite la representación personalizada de objetos y provee soporte para tipos genéricos de Java.

 
 
En el pom.xml se agregan las dependencias para descargar las librerías del repositorio Maven que son necesarias para activar el Gson.
            <dependency>
                        <groupId>com.google.code.gson</groupId>
                        <artifactId>gson</artifactId>
                        <version>1.7.1</version>
            </dependency> 
Se crean los objetos POJO Recibos, Documentos y DetRecibo que son la clase encargadas de almacenar los resultados del servicio, requeridos para que luego, utilizando atributos de la librería Gson, se logre indicar las dependencias con las propiedades JSON devueltas por el servicio web en RESTful, de este modo es posible convertir cadenas JSON formateado al tipo de objetos JAVA.
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "recibos")
public class Recibos {
            private Integer doccod;
            private Integer docrecitm;
 
            public Integer getDoccod() {
                        return doccod;
            }
            public void setDoccod(Integer doccod) {
                        this.doccod = doccod;
            }
            public Integer getDocrecitm() {
                        return docrecitm;
            }
            public void setDocrecitm(Integer docrecitm) {
                        this.docrecitm = docrecitm;
            }
}
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "documentos")
public class Documentos {
            private Integer doccod;
            private Integer docanonum;
            private Integer doccor;
            private String tpodoccod;
 
            public Integer getDoccod() {
                        return doccod;
            }
            public void setDoccod(Integer doccod) {
                        this.doccod = doccod;
            }
            public Integer getDocanonum() {
                        return docanonum;
            }
            public void setDocanonum(Integer docanonum) {
                        this.docanonum = docanonum;
            }
            public Integer getDoccor() {
                        return doccor;
            }
            public void setDoccor(Integer doccor) {
                        this.doccor = doccor;
            }
            public String getTpodoccod() {
                        return tpodoccod;
            }
            public void setTpodoccod(String tpodoccod) {
                        this.tpodoccod = tpodoccod;
            }
}
public class DetRecibo {
            private Integer doccod;
            private String concepto;
            private Double importe;
 
            public Integer getDoccod() {
                        return doccod;
            }
            public void setDoccod(Integer doccod) {
                        this.doccod = doccod;
            }
            public String getConcepto() {
                        return concepto;
            }
            public void setConcepto(String concepto) {
                        this.concepto = concepto;
            }
            public Double getImporte() {
                        return importe;
            }
            public void setImporte(Double importe) {
                        this.importe = importe;
            }
}
En alguna clase JAVA en la que se desea agregar el método en el cual se implementará la conversión de objetos con Gson; para hacer posible implementar la conversión de objetos al formato JAVA para que, de este modo, pueda ser enviado a través del servicio en el modelo SpringMVC logrando desplegar el servicio RESTful. Esto es posible gracias al el uso de dos métodos propios del Gson uno es el toJson(), utilizado para convertir objetos Java al formato JSON, y el otro método que es el más usado, el fromJson(), utilizado para convertir del formato JSON en objetos Java.
 
import com.google.gson.Gson;
@Controller
@Scope("session")
public class GestionController {
@Autowired
            private RestTemplate restTemplate;
@RequestMapping(value ="/recibo.htm" )
            public String recibos( ModelMap model , HttpServletRequest request, HttpServletResponse response ){
                        Documentos d = (Documentos) request.getSession().getAttribute("s_expediente");
                        try {
 
                    // Obtención de la cabecera del recibo
                                   String url = "http://localhost:8080/gestiondocumental-rest/rs/rest/usuarios-service/{anio}/{corr}/{tipo}/recibo";
                    // Obtención de datos en la respuesta del modelo REST
                                   String respuesta = restTemplate.getForObject(url , String.class, d.getDocanonum() ,d.getDoccor() , d.getTpodoccod());
                    // Uso del Gson para obtener datos de un Objeto
                    // Inicialización del objeto Gson
                                   Gson gson = new Gson();
                    // Obtención del objeto Recibos que almacena los datos enviados en la solicitud del mensaje, para ser convertidos del formato JSON en objetos Java
                    Recibos recibo= gson.fromJson(respuesta,Recibos.class);
                    // Guardando el objeto Recibo como atributo del requerimiento para posteriormente ser utilizado
                    request.setAttribute("recibo", recibo);
                    // Se agrega en el objeto model que es del tipo ModelMap para ser enviado en la respuesta que retornar en el parámetro model.
                    model.put("expediente", d);
                    // Obtención del detalle del recibo
                                    url = "http://localhost:8080/gestiondocumental-rest/rs/rest/usuarios-service/{anio}/{corr}/{tipo}/recibo/{recfact}/detalle";
                    // Obtención de datos en la respuesta del modelo REST
                                   respuesta = restTemplate.getForObject(url , String.class, d.getDocanonum() ,d.getDoccor() , d.getTpodoccod(),recibo.getDocrecfact());
                    // Uso del Gson para obtener un Listado del detalle del Objeto
                    // Inicialización del objeto Gson
                                   gson = new Gson();
                    // Aplicación de la parametrización de la colección que retornará la lista del detalle del recibo
                                   Type collectionType= new com.google.gson.reflect.TypeToken<List<DetRecibo>>(){}.getType();
                    // Obtención de la Lista del objetos DetRecibo que almacena los datos enviados como colección en la solicitud del mensaje, para ser convertidos del formato JSON en objetos Java
                    List<DetRecibo> listaPedidos= gson.fromJson(respuesta , collectionType);
                    // Guardando la lista de obejtos DetRecibo como atributo del requerimiento para posteriormente ser utilizado
                    request.setAttribute("lista", listaPedidos);                 
                        } catch (Exception e) {
                                    e.printStackTrace();
                                    request.setAttribute("MENSAJE", "No se encontraron datos.");
                        }
                        return "recibo";
            }
}


lunes, 15 de octubre de 2012


Spring Secutirty

 
Primero se crean tablas que serán utilizados para el propósito del Spring Security. Uno para el registro de usuarios y otro para el registro de perfiles. El siguiente script servirá para agregar las tablas NSBUSR01 y AUTHORITIES en el MySql.

 

CREATE TABLE `NSBUSR01` (
  `USRCOD`    int(4) not null,
  `USRAPEPAT` varchar(15),
  `USRAPEMAT` varchar(15),
  `USRNOM`    varchar(20),
  `USRLOG`    varchar(10),
  `CLAVE` varchar(50),
  `ESTADO` int(11),
  PRIMARY KEY (`USRCOD`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `NSBUSR01` VALUES
(1, 'SILVA', 'DIOS', 'MARYURI FABIOLA', 'MSILVA', ' e10adc3949ba59abbe56e057f20f883e ', 1)
,(3, 'MARTINEZ', 'JHON', 'LORENA', 'LMARTINEZ ', e10adc3949ba59abbe56e057f20f883e ', 1);

CREATE TABLE `AUTHORITIES` (
            `AUTHORITHI` varchar(50) not null,
            `USERNAME` varchar(50) not null
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `AUTHORITIES` VALUES
('ROLE_USER', 'MSILVA')
,('ROLE_ADMIN', 'MSILVA')
,('ROLE_USER', 'LMARTINEZ');

 

En el pom.xml agregar las dependencias para que el Maven descargue las librerías necesarias para activar el Spring Security.

 

     <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-core</artifactId>
        <version>3.0.3.RELEASE</version>
     </dependency>
     <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>3.0.3.RELEASE</version>
    </dependency>
     <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-acl</artifactId>
        <version>3.0.3.RELEASE</version>
    </dependency>
     <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-taglibs</artifactId>
        <version>3.0.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>3.0.3.RELEASE</version>
    </dependency>

 

Luego agregar dentro de la carpeta WEB-INF un archivo con nombre security-config.xml, en donde se especifica el tag principal <http> en donde se indica que carpetas y direcciones no se aplicará la seguridad, como es el caso de la página del login.htm que siempre deberá mostrarse a todos los usuarios. Además dentro de este tag se inidica el tag <form-login> en donde se especifica las páginas por defecto (default-target-url), a donde redireccionará en caso de hacer loguin (login-page) o en caso surja algún error de autenticación (authentication-failure-url). Así mismo hay un tag para especificar la página que redireccionará en caso se haga logout (logout-success-url) en el tag <logout>. Finalmente, en otro tag principal < authentication-manager> especifica el alias del servicio que realizará la autenticación (user-service-ref) en al tag <authentication-provider> y también se puede especificar el tipo de encriptación de la contraseña (hash) en el tag <password-encoder>.

 

<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns="http://www.springframework.org/schema/security"
         xmlns:b="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">

        <!-- Configure Spring Security -->
        <http auto-config="true">
                <intercept-url pattern="/css/*" filters="none"/>
                <intercept-url pattern="/img/*" filters="none"/>
                <intercept-url pattern="/js/*" filters="none"/>
                <intercept-url pattern="/images/*" filters="none"/>
                <intercept-url pattern="/login.htm" filters="none"/>
                <intercept-url pattern="/redirect.jsp" filters="none"/>
                <intercept-url pattern="/**" access="ROLE_USER"/>
                <form-login login-page="/login.htm"
                                        default-target-url="/home.htm"
                                        authentication-failure-url="/login.htm?login_error=1"
                                        always-use-default-target="true" />
                <http-basic/>               
                <logout invalidate-session="true" logout-success-url="/login.htm" />                               
                <remember-me />
        </http>
 
        <authentication-manager>
                <authentication-provider user-service-ref="userLoginService" >                       
                     <password-encoder hash="md5" />                       
                </authentication-provider>          
        </authentication-manager>
</b:beans>

 

Luego en el applicationContext.xml agregar la importación del archivo de configuración del spring security:

 

<import resource="security-config.xml" />

 

Se agrega el modelo de la clase objeto UsuariosSystem.java que refleja los atributos del usuario en la base de datos con sus getter y setters. Además contiene la implementación de la lista para obtener los perfiles de los usuarios, así como la implementación del constructor UsuariosSystem que servirá al spring security para realizar la consulta de la autorización de usuarios en el loguin.

 

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;

public class UsuariosSystem extends User{

            private static final long serialVersionUID = 1L;
 
            private Integer usrcod;
            private String usrapepat;
            private String usrapemat;
            private String usrnom;
            private String usrlog;
            private String clave;
            private Integer estado;

             public static UsuariosSystem getUsuarioBean() {
                         UsuariosSystem nu = (UsuariosSystem)(SecurityContextHolder.getContext().getAuthentication().getPrincipal());
         if(nu != null) {
             return nu;
         }
         else return null;
             }

             public static List<GrantedAuthority> uno(){
         List<GrantedAuthority> oo = new ArrayList<GrantedAuthority>();
         oo.add(new GrantedAuthorityImpl("IS_AUTHENTICATED_ANONYMOUSLY") );
         return oo;
             }

             public UsuariosSystem(){
                        super("default", "default", true, true, true, true , uno() );
             }

            public UsuariosSystem(String username, String password, boolean enabled, Collection<GrantedAuthority> authorities) {
                          super(username, password, enabled, true, true, true, authorities);
          this.estado = enabled==true ? 1 : 0;
          this.usrlog = username;
          this.clave = password;
            }         

            public UsuariosSystem(String username, String password, boolean enabled,List<GrantedAuthority> authorities,
                                   Integer usrcod, String usrapepat, String usrapemat,
                                   String usrnom, String usrlog
) {
                        super(username, password, enabled, true, true, true, authorities);
                        this.estado = enabled==true ? 1 : 0;
        this.usrlog = username;
        this.clave = password;
                        this.usrcod = usrcod;
                        this.usrapepat = usrapepat;
                        this.usrapemat = usrapemat;
                        this.usrnom = usrnom;
                        this.usrlog = usrlog;
            }
 
            public Integer getUsrcod() {
                        return usrcod;
            }
            public void setUsrcod(Integer usrcod) {
                        this.usrcod = usrcod;
            }
            public String getUsrapepat() {
                        return usrapepat;
            }
            public void setUsrapepat(String usrapepat) {
                        this.usrapepat = usrapepat;
            }
            public String getUsrapemat() {
                        return usrapemat;
            }
            public void setUsrapemat(String usrapemat) {
                        this.usrapemat = usrapemat;
            }
            public String getUsrnom() {
                        return usrnom;
            }
            public void setUsrnom(String usrnom) {
                        this.usrnom = usrnom;
            }
            public String getUsrlog() {
                        return usrlog;
            }
            public void setUsrlog(String usrlog) {
                        this.usrlog = usrlog;
            }
            public String getClave() {
                        return clave;
            }
            public void setClave(String clave) {
                        this.clave = clave;
            }
            public Integer getEstado() {
                        return estado;
            }
            public void setEstado(Integer estado) {
                        this.estado = estado;
            }
}

 

En la clase UsuariosDAOImpl.java se implementa el método obtenerUsuarioPorUsername para obtener datos adicionales del usuario

 

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.stereotype.Repository;
import pe.com.munmiraflores.gestiondocumental.domain.UsuariosSystem;

@Repository
public class UsuariosDAOImpl  extends BaseDAO implements UsuarioDao{

            @Override
            public UsuariosSystem obtenerUsuarioPorUsername(String username) {
                        Connection con = null;
                        PreparedStatement stmt = null;
                        ResultSet rs = null;
                        UsuariosSystem usr = null;
                        try {
                                   String query = "Select * from nsbusr01 where usrlog = ? ";
                                   con = ConexionBD.obtenerConexion();
                                   stmt = con.prepareStatement(query);
                                   stmt.setString(1, username);
                                   rs = stmt.executeQuery();
                                   if (rs.next()) {
                                               usr = new UsuariosSystem(rs.getString("usrlog"), rs.getString("clave"), rs.getInt("estado")==1?true:false, UsuariosSystem.uno() );
                                               usr.setUsrapepat( rs.getString("usrapepat"));
                                   }
                        } catch (SQLException e) {
                                   System.err.println(e.getMessage());
                        } finally {
                                   this.cerrarResultSet(rs);
                                   this.cerrarStatement(stmt);
                                   this.cerrarConexion(con);
                        }
                        return usr;
            }
}

 

En la clase AutenticacionJdbcDaoImpl.java que extiende de una interface en las librerías Spring, el org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl el cual especifica la implementación del método loadUserByUsername que recibe como parámetro el nombre del usuario que será autenticado para loguear al sistema. Y a su vez, en el método loadUserByUsername, se deberá especificar la ejecución del método setUsersByUsernameQuery el cual recibe la consulta que realizará la validación del usuario y del método setAuthoritiesByUsernameQuery el cual reciben las consultas para obtener el perfil del usuario logueado. Además, se ha agregado la ejecución del método obtenerUsuarioPorUsername que viene de la clase UsuariosDAOImpl  para obtener datos adicionales como el nombre y apellidos del usuario logueado.

 

import javax.sql.DataSource;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;
import org.springframework.stereotype.Repository;
import pe.com.munmiraflores.gestiondocumental.dao.UsuarioDao;
import pe.com.munmiraflores.gestiondocumental.domain.UsuariosSystem;

@Repository("userLoginService")
public class AutenticacionJdbcDaoImpl extends JdbcDaoImpl{

            private Logger logger = Logger.getLogger(AutenticacionJdbcDaoImpl.class);

            @Autowired
            public AutenticacionJdbcDaoImpl(DataSource dataSource){
                        setDataSource(dataSource);
            }

            @Autowired
            private UsuarioDao usuarioDao;

            @Override
            public UserDetails loadUserByUsername(String username) {
                        try {
                                   this.setUsersByUsernameQuery("SELECT u.usrlog as username,u.clave as password, u.estado as enabled  FROM nsbusr01 u WHERE u.usrlog = ?");
                                   this.setAuthoritiesByUsernameQuery("SELECT  username ,authority FROM authorities WHERE username = ?");
                                   UserDetails user = super.loadUserByUsername(username);
                                   logger.debug("usuario login "+user.toString());
                                   UsuariosSystem usuario =  usuarioDao.obtenerUsuarioPorUsername(username);
                                   UsuariosSystem ubean = new UsuariosSystem(
                                                           user.getUsername(),
                                                           user.getPassword(),
                                                           user.isEnabled(),
                                                           user.getAuthorities() );
                                   ubean.setUsrlog(usuario.getUsrlog());
                                   ubean.setClave(user.getPassword());
                                   ubean.setEstado( user.isEnabled()==true?1:0);
                                   ubean.setUsrapemat( usuario.getUsrapemat());
                                   ubean.setUsrapepat( usuario.getUsrapepat());
                                   logger.debug("*********"+ubean.toString());
                                   return ubean;  
                        } catch (Exception e) {
                                   e.printStackTrace();
                                   throw new UsernameNotFoundException("No hay notaria relacionada a este usuario");
                        }
            }         
}

 

Se agregan en el archivo WEB-INF\web.xml el filtro y el mapeo del filtro del Spring Security.

 

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
   <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

 

Al momento de declarar el form en el JSP se llama en el “action” al método que aplicará la seguridad del spring. j_spring_security_check es el nombre estándar que llama al servicio que realizará el loguin.

 

<form name="f" action="${pageContext.request.contextPath}/j_spring_security_check" method="post">

 

Finalmente, con el siguiente código HTML y el tag c:if de las librerías del JSTL insertado en un JSP se permite mostrar mensajes de las excepciones en caso no se haya logrado hacer loguin.

 

<c:if test="${not empty param.login_error}">
                        <div class="errors" style="color: #000;" align="right">
                                   No pudo ingresar al sistema, Intentelo nuevamente.<br />
                                   Razon: ${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}
                        </div>
            </c:if>