Spring Security Formulario de Login JSP

Este es el segundo tutorial de la serie de cursos sobre seguridad con Spring Security Framework, hoy aprenderemos como personalizar o crear nuestro propio formulario de login para nuestras páginas web, seguimos trabajando sobre el tutorial anterior por lo que es importante que lo leas si no tienes los conocimientos básico sobre esta tecnología, el enlace: introducción a la seguridad básica.

Para este proyecto de ejemplo, la configuración es exactamente la misma que la mostrada previamente, las modificaciones se harán sobre la clase WebSecConfig.

@Configuration
@EnableWebSecurity
public class WebSecConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureAuth(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user").password("user").roles("USER").and()
                .withUser("admin").password("admin").roles("USER", "ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin().loginPage("/login").permitAll()
                .and()
                .logout().permitAll();
    }
}

Le prestamos atención al método configure() lo demás ya lo hemos explicado, este método configura la seguridad para las peticiones HTTP, se explica de la siguiente manera:

  1. .anyRequest().authenticated() se requiere estar autenticado para todas las peticiones.
  2. .formLogin().loginPage("/login").permitAll() el formulario será definido en la página login.jsp que crearemos más adelante, las peticiones a esta página no requieren autenticación, cualquier usuario puede acceder a ella.
  3. .logout().permitAll() activa el cierre de sesión mediante la URL "/logout", cualquier usuario puede acceder a esta URL.

Lo que prosigue es crear el formulario JSP, para que funcione correctamente debe tener dos campos username y password, estos deben ser enviados usando el método POST a la URL "/login".

<%@ page contentType="text/html" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link href="static/css/login.css" type="text/css" rel="stylesheet" />
        <title>Login Form</title>
    </head>
    <body>

        <div class="main">
            <div class="box">

                <h1 class="title">Iniciar Sesión</h1>

                <c:url value="/login" var="loginUrl"/>

                <form action="${loginUrl}" method="post">

                    <c:if test="${param.error != null}">
                        <p class="error">Username y password incorrectos, intentalo nuevamente.</p>
                    </c:if>

                    <c:if test="${param.logout != null}">
                        <p class="logout">La sesión ha sido cerrada correctamente.</p>
                    </c:if>

                    <div>
                        <label for="username">Nombre</label>
                        <input type="text" id="username" name="username"/>
                    </div>

                    <div>
                        <label for="password">Contraseña</label>
                        <input type="password" id="password" name="password"/>
                    </div>

                    <button type="submit" class="btn">Log in</button>
                </form>

            </div>
        </div>

    </body>
</html>

Para verificar si tenemos un error en el inicio de sesión, es decir el nombre de usuario o contraseña son incorrectos verificamos si el parámetro error está presente en la URL, cuando se produce un error somos enviados a la URL: "/login?error", creamos un mensaje de error si este parámetro existe.

<c:if test="${param.error != null}">
    <p class="error">Username y password incorrectos, intentalo nuevamente.</p>
</c:if>

De modo similar somos enviados a la URL "/login?logout" cuando cerramos la sesión, también podemos mostrar un mensaje si lo deseamos.

Lo que sigue es asegurarnos de que el controlador apunte a la vista JSP que acabamos de crear, para ello nos dirigimos a la clase WebAppConfig y sobre-escribimos el método addViewControllers de este modo:

@EnableWebMvc
@Configuration
@ComponentScan(basePackages = {"carmelo.spring.controller"})
public class WebAppConfig extends WebMvcConfigurerAdapter {

    // ...

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
    }
}

Si probamos la aplicación web que hemos desarrollado, veremos:

Tutorial Spring Security - formulario de login

Puedes introducir un nombre de usuario y/o contraseña erróneo y mostrará el mensaje de error, se puede mostrar información especifica de la excepción que se ha producido, pero esto puede ser una vulnerabilidad de seguridad.

Antes de finalizar veamos como podemos obtener el nombre del usuario actual, esto lo haremos desde el controlador y usaremos el método SecurityContextHolder.getContext().getAuthentication() para obtener la información de autenticación y autorización del correspondiente usuario.

@Controller
public class HomeController {

    @RequestMapping(value = {"/", "/home"})
    public String home(Model model) {

        model.addAttribute("nombre_usuario", SecurityContextHolder
                .getContext().getAuthentication().getName());

        return "home";
    }

    // ...
}

En la página JSP solo debemos acceder al atributo llamado nombre_usuario, por ejemplo:

// ...
<h4>Bienvenido: ${nombre_usuario}</h4>
// ...

Antes de terminar debemos mencionar que para este ejemplo hemos deshabilitado la protección CSRF, además si nuestro formulario de inicio de sesión utiliza algún archivo CSS, JS, etc., debemos desbloquear las URL respectivas, con esto la configuración de seguridad queda de esta manera:

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/static/**").permitAll()
            .anyRequest().authenticated()       
            .and()
            .formLogin().loginPage("/login").permitAll()
            .and()
            .logout().permitAll();
}

Hemos finalizado este tutorial por ahora, en la siguiente entrega agregaremos una base de datos para almacenar la información de los usuarios de nuestro sitio web, hasta la próxima.

Descargar proyecto: formulario de login.zip

Comentarios

Temas relacionados

Entradas populares de este blog

tkinter Grid

Histogramas OpenCV Python

tkinter Canvas

Conectar SQL Server con Java