<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Códice | Entradas sobre «spring security»</title><description>Feed RSS de publicaciones etiquetadas con spring security</description><link>https://javguerra.github.io/</link><item><title>Logout personalizado con Spring Security</title><link>https://javguerra.github.io/blog/logout-spring-security</link><guid isPermaLink="true">https://javguerra.github.io/blog/logout-spring-security</guid><description>Limpiando el contexto de seguridad sin borrar la cookie</description><pubDate>Sat, 13 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://javguerra.github.io/_astro/cookies.CQlbddQu_TNB6F.webp&quot; alt=&quot;cookies&quot; style=&quot;max-width: 100%; height: auto;&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Etiquetas:&lt;/strong&gt; &lt;em&gt;#código&lt;/em&gt;, &lt;em&gt;#java&lt;/em&gt;, &lt;em&gt;#spring boot&lt;/em&gt;, &lt;em&gt;#spring security&lt;/em&gt;, &lt;em&gt;#ciberseguridad&lt;/em&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;En un &lt;a href=&quot;/blog/notificaciones-thymeleaft&quot;&gt;artículo anterior&lt;/a&gt; he usado variables de sesión para guardar información de la aplicación: mensajes para el usuario, aviso de cookies… Puede que, cuando el usuario salga de su sesión, queramos conservar estos datos que seguirán siendo útiles aunque no esté autenticado. En esta entrada muestro mi solución usando Spring Security.&lt;/p&gt;
&lt;p&gt;Se asume que el lector tiene conocimientos generales de Spring Boot y Spring Security para aplicar el contenido.&lt;/p&gt;
&lt;h1 id=&quot;el-contexto-de-seguridad&quot;&gt;El contexto de seguridad&lt;/h1&gt;
&lt;p&gt;El primer paso en el proceso de logout que lleva a cabo Spring Security es invalidar la sesión del usuario. Esto significa que Spring Security elimina cualquier información asociada con la sesión del usuario, como datos de estado de sesión almacenados en el servidor o en cookies (borra la información, pero no la cookie). Al invalidar la sesión, se asegura de que el usuario ya no pueda acceder a la aplicación como si estuviera autenticado.&lt;/p&gt;
&lt;p&gt;Después de invalidar la sesión, Spring Security también limpia el contexto de seguridad actual. Esto incluye eliminar cualquier token de Authentication que represente al usuario autenticado, asegurando que el usuario ya no sea reconocido como autenticado en la aplicación.&lt;/p&gt;
&lt;p&gt;Pero en este caso no interesa ese borrado completo, sino sólo la información de autenticación. Para ello debo codificar mi propio logout limpiando el contexto de seguridad pero sin invalidar la sesión.&lt;/p&gt;
&lt;h1 id=&quot;tomando-el-control-de-logout&quot;&gt;Tomando el control de Logout&lt;/h1&gt;
&lt;p&gt;Como sabemos, para configurar Spring Security se usa la clase &lt;code&gt;SecurityConfig.class&lt;/code&gt;, que generalmente incluye el componente &lt;code&gt;SecurityFilterChain&lt;/code&gt;, fundamental para establecer filtros a las peticiones HTTP que se reciben en la aplicación. En este ejemplo me centraré en la parte de su configuración relativa al logout.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Configuration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;EnableWebSecurity&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  SecurityConfig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Bean&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; SecurityFilterChain &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;securityFilterChain&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(HttpSecurity &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)  &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Exception {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        http.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;authorizeHttpRequests&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(authRequest &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; authRequest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;requestMatchers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(HttpMethod.POST, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/logout&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;permitAll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;anyRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;authenticated&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;logout&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(logout &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; logout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;logoutUrl&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/logout&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;permitAll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; http.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Con &lt;code&gt;...&lt;/code&gt; indico que el código puede ser más amplio y contener otras configuraciones.&lt;/p&gt;
&lt;p&gt;En la línea &lt;code&gt;.requestMatchers(HttpMethod.POST, &quot;/logout&quot;).permitAll()&lt;/code&gt; estoy permitiendo el acceso a la ruta personalizada para llevar a cabo el logout. Realmente, esto no sería necesario al incluir &lt;code&gt;.permitAll()&lt;/code&gt; después de &lt;code&gt;logoutUrl(&quot;/logout&quot;)&lt;/code&gt;. Tampoco sería necesario porque la ruta &lt;code&gt;/logout&lt;/code&gt; está disponible por defecto. No obstante, esto puede ser útil si decidimos usar otra ruta distinta a &lt;code&gt;/logout&lt;/code&gt; en la aplicación.&lt;/p&gt;
&lt;p&gt;Para la gestión del token del usuario, será necesario definir un controlador propio para la ruta &lt;code&gt;logout&lt;/code&gt;. Algo similar a esto:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Slf4j&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Controller&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogoutController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;RequestMapping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/logout&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; String &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;logout&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        log.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;logout&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        SecurityContextHolder.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setAuthentication&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // cosas que hacer tras el cierre de sesión aquí&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;logout&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;La información de sesión se guarda en una cookie llamada &lt;code&gt;JSESSIONID&lt;/code&gt;, que contendrá las variables de sesión, incluido el token de autenticación.&lt;/p&gt;
&lt;p&gt;Con &lt;code&gt;SecurityContextHolder.getContext().setAuthentication(null);&lt;/code&gt; elimino el token de autenticación, pero sin borrar toda la información de la cookie, como las variables de sesión.&lt;/p&gt;
&lt;p&gt;Después de esto, puedo realizar algunas acciones asociadas al cierre y redirigir al login, o como en este caso, mostrar la vista &lt;code&gt;logout&lt;/code&gt; para mostrar un mensaje de despedida.&lt;/p&gt;
&lt;h1 id=&quot;refinando-el-logout&quot;&gt;Refinando el logout&lt;/h1&gt;
&lt;p&gt;Al usar &lt;code&gt;null&lt;/code&gt; elimino el token de autenticación del usuario, pero puede que, en la plantilla que devuelvo con return (&lt;code&gt;logout&lt;/code&gt; en el caso anterior), sea necesario usar el contexto de seguridad, por ejemplo mostrando una información u otra en un fragmento de la plantilla si estamos autenticados o no. Con este método, ni &lt;code&gt;sec:authorize=&quot;isAnonymous()&quot;&lt;/code&gt; ni &lt;code&gt;sec:authorize=&quot;isAuthenticated()&quot;&lt;/code&gt; funcionarán en Thymeleaft, ya que ahora no existe el token que indique si el usuario es anónimo o está autenticado.&lt;/p&gt;
&lt;p&gt;Esto ocurre sólo para la vista asociada al controlador que es llamada tras borrar el token, pero no ocurre así para las siguientes vistas, en las que parece que el token es regenerado como anónimo.&lt;/p&gt;
&lt;p&gt;Entonces, si en la siguiente vista no vamos a usar la autenticación, será suficiente con usar &lt;code&gt;null&lt;/code&gt;, pero si no es así, entonces hay que cambiar el token en vez de eliminarlo, pero Spring Boot no tiene un token por defecto que pueda usar, así que debo construir uno.&lt;/p&gt;
&lt;p&gt;Primeramente añado el siguiente código en&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Bean&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AnonymousAuthenticationToken &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;anonymousAuthenticationToken&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    List&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;GrantedAuthority&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt; authorities &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Collections.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;singletonList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SimpleGrantedAuthority&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ROLE_ANONYMOUS&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AnonymousAuthenticationToken&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ANONYMOUS_USER&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ANONYMOUS_USER&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, authorities);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Que me permitirá crear &lt;code&gt;anonymousAuthenticationToken&lt;/code&gt; como un &lt;code&gt;Bean&lt;/code&gt;. Este método es responsable de crear e inicializar el objeto &lt;code&gt;AnonymousAuthenticationToken&lt;/code&gt;. Este token es utilizado por Spring Security para representar la autenticación de usuarios anónimos dentro de una aplicación.&lt;/p&gt;
&lt;p&gt;El método realiza las siguientes acciones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Inicialización de Autoridades&lt;/strong&gt;: Primero, creo una lista (&lt;code&gt;List&amp;lt;GrantedAuthority&amp;gt;&lt;/code&gt;) con un solo elemento, que es una instancia de &lt;code&gt;SimpleGrantedAuthority&lt;/code&gt; con el rol &lt;code&gt;&quot;ROLE_ANONYMOUS&quot;&lt;/code&gt;. Las autoridades (o roles) determinan los privilegios que tiene un usuario dentro de la aplicación. En este caso, asigno al usuario anónimo el rol de &lt;code&gt;ROLE_ANONYMOUS&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Creación del Token&lt;/strong&gt;: Luego, utilizo esta lista de autoridades para construir un nuevo &lt;code&gt;AnonymousAuthenticationToken&lt;/code&gt;, pasando también dos cadenas de texto (&lt;code&gt;&quot;ANONYMOUS_USER&quot;&lt;/code&gt;) como nombre y detalles del usuario. Estos valores pueden ser personalizados según sea necesario.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ya puedo usar el token en el controlador, como se muestra:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Slf4j&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;RequiredArgsConstructor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Controller&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogoutController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AnonymousAuthenticationToken anonymousAuthenticationToken;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;RequestMapping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/logout&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; String &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;logout&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        log.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;logout&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        SecurityContextHolder.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setAuthentication&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(anonymousAuthenticationToken);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // cosas que hacer tras el cierre de sesión aquí&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;logout&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ahora sí, el usuario será anónimo, y cualquier comprobación en la plantilla Thymeleaft que incluya &lt;code&gt;sec:authorize=&quot;isAnonymous()&quot;&lt;/code&gt; permitirá que la etiqueta HTML que lo use sea mostrada.&lt;/p&gt;
&lt;h1 id=&quot;consideraciones&quot;&gt;Consideraciones&lt;/h1&gt;
&lt;p&gt;Tal vez podría crearse un servicio al que llamar desde el controlador para gestionar el logout, o un manejador propio &lt;code&gt;CustomLogoutHandler&lt;/code&gt; que realice esta función de cierre de sesión sin la necesidad de crear un controlador, y que se use directamente desde &lt;code&gt;SecurityConfig.class&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Se han de tener en cuenta las consideraciones de seguridad relacionadas con este método. Mantener información de la sesión de usuario una vez se lleva a cabo el logout no siempre es seguro, y se deben controlar las posibles fugas de información para evitar problemas.&lt;/p&gt;
&lt;h1 id=&quot;un-ejemplo&quot;&gt;Un ejemplo&lt;/h1&gt;
&lt;p&gt;Puedes ver el código que implementan esta funcionalidad en el repositorio de la aplicación &lt;a href=&quot;/blog/cartelera-daw&quot;&gt;Cartelera DAW&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/JavGuerra/cartelera-daw&quot;&gt;Repositorio de Cartelera DAW&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mira también el artículo donde se usan las variables de sesión que quiero preservar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/notificaciones-thymeleaft&quot;&gt;Notificaciones con Thymeleaft&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><enclosure url="https://javguerra.github.io/_astro/cookies.CQlbddQu_TNB6F.webp"/><category>código</category><category>java</category><category>spring boot</category><category>spring security</category><category>ciberseguridad</category><author>JavGuerra</author></item><item><title>Cartelera DAW</title><link>https://javguerra.github.io/blog/cartelera-daw</link><guid isPermaLink="true">https://javguerra.github.io/blog/cartelera-daw</guid><description>Proyecto final de FPGS DAW con Java y Spring Boot</description><pubDate>Thu, 20 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://javguerra.github.io/_astro/cartelera-daw.CwIRaY5E_xNKzt.webp&quot; alt=&quot;Logo cartelera DAW&quot; style=&quot;max-width: 100%; height: auto;&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Etiquetas:&lt;/strong&gt; &lt;em&gt;#portfolio&lt;/em&gt;, &lt;em&gt;#web&lt;/em&gt;, &lt;em&gt;#java&lt;/em&gt;, &lt;em&gt;#spring boot&lt;/em&gt;, &lt;em&gt;#bootstrap&lt;/em&gt;, &lt;em&gt;#thymeleaft&lt;/em&gt;, &lt;em&gt;#spring security&lt;/em&gt;, &lt;em&gt;#accesibilidad&lt;/em&gt;, &lt;em&gt;#responsive&lt;/em&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Recientemente he presentado mi proyecto fin de estudios de Formación Profesional de Grado Superior DAW. Era algo que llevaba aparcado durante demasiado tiempo y finalmente esta etapa se ha cerrado.&lt;/p&gt;
&lt;p&gt;El proyecto  ha consistido en una aplicación web monolítica, desarrollada en Java, usando el framework Spring Boot, y ha sido desplegada en el servicio de Railway.com.&lt;/p&gt;
&lt;h2 id=&quot;el-proyecto&quot;&gt;El proyecto&lt;/h2&gt;
&lt;p&gt;El proyecto Cartelera DAW desarrolla una plataforma web para mostrar información cinematográfica cuyos usuarios potenciales son los espectadores y las distribuidoras de películas, cines y salas de proyección.&lt;/p&gt;
&lt;p&gt;La plataforma, que está basada en &lt;strong&gt;Java&lt;/strong&gt; y &lt;strong&gt;Spring Boot&lt;/strong&gt;, utiliza un patrón Modelo-Vista-Controlador y una arquitectura cliente-servidor, haciendo uso del IDE &lt;strong&gt;IntelliJ IDEA&lt;/strong&gt;, de &lt;strong&gt;Maven&lt;/strong&gt; para la gestión del proyecto, de &lt;strong&gt;Git&lt;/strong&gt; y &lt;strong&gt;GitHub&lt;/strong&gt; para el versionado de código, de &lt;strong&gt;MySQL&lt;/strong&gt; e &lt;strong&gt;Hibernate&lt;/strong&gt; para la gestión de la base de datos y de una &lt;strong&gt;configuración LAMP dockerizada&lt;/strong&gt; para las pruebas. Para el despliegue se utilizaron tecnologías como &lt;strong&gt;Docker&lt;/strong&gt; y metodologías &lt;strong&gt;CI/CD&lt;/strong&gt;. Para el frontend se ha empleado el gestor de plantillas &lt;strong&gt;Tymeleaft&lt;/strong&gt; y &lt;strong&gt;Bootstrap&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Adicionalmente se proponen una serie de estrategias comerciales para garantizar la sostenibilidad del modelo empresarial del proyecto.&lt;/p&gt;
&lt;p&gt;Se elaboró una memoria de 70 páginas y una presentación.&lt;/p&gt;
&lt;p&gt;El objetivo era aprender y usar tecnologías nuevas no estudiadas en DAW.&lt;/p&gt;
&lt;p&gt;La calificación final ha sido de 9 de 10, y se ha llevado a cabo en un periodo de tres semanas.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JavGuerra/cartelera-daw/main/src/main/resources/static/img/banner.png&quot; alt=&quot;Pantalla Cartelera DAW&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cartelera-daw.up.railway.app/&quot;&gt;&lt;button&gt;Ver Cartelera DAW en línea&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;la-formación-previa&quot;&gt;La formación previa&lt;/h2&gt;
&lt;p&gt;Pero el proyecto no partía de cero. Durante los meses de enero y febrero, y hasta el 9 de marzo de 2023, participé en un curso de especialización en Java + Spring de la Fundación Adecco dentro del Proyecto Digital School Erasmus+&lt;/p&gt;
&lt;p&gt;Se trataba de una formación mentorizada que incluía un trabajo en grupo para desarrollar una aplicación web. En mi grupo de trabajo me encargué de la coordinación del equipo mediante Trello y de la planificación de las funcionalidades de la aplicación y las propuesta de mejora de la app. El grupo se llamaba Cinéfilos, y Cartelera DAW bebe de la estructura simple de aquella práctica que me sirvió para entender cómo funciona el framework.&lt;/p&gt;
&lt;p&gt;El proyecto ahora presentado ha cambiado mucho desde aquella versión, tanto en su estructura como en su diseño. Partía de un código inconcluso donde sólo se habían implementado los CRUDs básicos, con fallos de integridad y sin funcionalidades mínimas, pero ahora la aplicación ha sido probada y revisada en profundidad, y cuenta con características que refuerzan sus funcionalidades.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/JavGuerra/cartelera-daw&quot;&gt;&lt;button&gt;Ir al repositorio del proyecto&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;En el curso, así como en la práctica, obtuve una calificación de 10/10.&lt;/p&gt;
&lt;h2 id=&quot;características&quot;&gt;Características&lt;/h2&gt;
&lt;p&gt;Además de los requisitos solicitados para el MVP, en la app se ha implementado:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Seguridad de rutas&lt;/li&gt;
&lt;li&gt;Registros de usuario&lt;/li&gt;
&lt;li&gt;Validaciones de formularios&lt;/li&gt;
&lt;li&gt;Automatizaciones&lt;/li&gt;
&lt;li&gt;Documentación con JavaDoc&lt;/li&gt;
&lt;li&gt;Implementación de Logs&lt;/li&gt;
&lt;li&gt;Notificaciones&lt;/li&gt;
&lt;li&gt;Despliegue dockerizado&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cuenta con:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Portada dinámica&lt;/li&gt;
&lt;li&gt;Diseño responsive&lt;/li&gt;
&lt;li&gt;Diseño accesible&lt;/li&gt;
&lt;li&gt;Aviso legal y privacidad&lt;/li&gt;
&lt;li&gt;Aviso de cookies&lt;/li&gt;
&lt;li&gt;Ayuda en línea&lt;/li&gt;
&lt;li&gt;Spinner loader&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Logo Cartelera-DAW&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;@/assets/img/cartelera-daw.svg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;desarrollo-y-despliegue&quot;&gt;Desarrollo y despliegue&lt;/h2&gt;
&lt;p&gt;Tanto en el desarrollo como en el despliegue ha jugado un papel importante Docker.&lt;/p&gt;
&lt;p&gt;La BBDD MySQL y PHPMyAdmin han sido lanzados usando contenedores gestionados con la herramienta Portainer.&lt;/p&gt;
&lt;p&gt;El despliegue se lleva a cabo tomando el código fuente y, mediante un dockerfile, construyendo la imagen del contenedor que es lanzado en el servidor.&lt;/p&gt;
&lt;p&gt;Spring Boot contiene un servidor Tomcat encargado de servir las páginas de la aplicación.&lt;/p&gt;
&lt;h2 id=&quot;indicaciones-de-instalación&quot;&gt;Indicaciones de instalación&lt;/h2&gt;
&lt;p&gt;Tras clonar el repositorio, es necesario crear un usuario en la BBDD relacional llamado «cartelera-daw» con el password que deseemos. Estos datos, así como el puerto por defecto de la app (8082), pueden ser introducidos en el fichero «aplication.propieties», en la carpeta resources.&lt;/p&gt;
&lt;p&gt;Cada vez que se inicia la aplicación, esta recarga los datos en la BBDD.&lt;/p&gt;
&lt;p&gt;Una vez iniciada la aplicación en local, se puede acceder a ella en la dirección: &lt;code&gt;http://localhost:8082&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;El acceso al panel de administración requiere de usuario y contraseña. Por defecto, la aplicación tiene un usuario «admin» y su contraseña es «admin».&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ADVERTENCIA&lt;/strong&gt;: Se recomienda que, tras el primer acceso, la contraseña de admin sea cambiada o se cree una nueva cuenta de usuario desde la que eliminar la cuenta «admin».&lt;/p&gt;
&lt;h2 id=&quot;licencia&quot;&gt;Licencia&lt;/h2&gt;
&lt;p&gt;Sobre el código fuente: GNU GENERAL PUBLIC LICENSE Version 3&lt;/p&gt;
&lt;h2 id=&quot;enlaces&quot;&gt;Enlaces&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JavGuerra/cartelera-daw/a79cd41c51299dd3897d989ea8e045ea5f894ac7/src/main/resources/static/img/qr-app.svg&quot; alt=&quot;QR enlace a la Aplicación&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cartelera-daw.up.railway.app/&quot;&gt;Aplicación&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/JavGuerra/cartelera-daw&quot;&gt;Repositorio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><enclosure url="https://javguerra.github.io/_astro/cartelera-daw.CwIRaY5E_xNKzt.webp"/><category>portfolio</category><category>web</category><category>java</category><category>spring boot</category><category>bootstrap</category><category>thymeleaft</category><category>spring security</category><category>accesibilidad</category><category>responsive</category><author>JavGuerra</author></item><item><title>Recursos TIC</title><link>https://javguerra.github.io/blog/recursos-tic</link><guid isPermaLink="true">https://javguerra.github.io/blog/recursos-tic</guid><description>Proyecto final del curso de Java, Spring Boot y testing.</description><pubDate>Wed, 11 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://javguerra.github.io/_astro/recursos-tic.DMmpqNPg_ZqU5V8.webp&quot; alt=&quot;Banner Recursos TIC&quot; style=&quot;max-width: 100%; height: auto;&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Etiquetas:&lt;/strong&gt; &lt;em&gt;#portfolio&lt;/em&gt;, &lt;em&gt;#web&lt;/em&gt;, &lt;em&gt;#java&lt;/em&gt;, &lt;em&gt;#spring boot&lt;/em&gt;, &lt;em&gt;#bootstrap&lt;/em&gt;, &lt;em&gt;#thymeleaft&lt;/em&gt;, &lt;em&gt;#spring security&lt;/em&gt;, &lt;em&gt;#accesibilidad&lt;/em&gt;, &lt;em&gt;#responsive&lt;/em&gt;, &lt;em&gt;#selenium&lt;/em&gt;, &lt;em&gt;#api&lt;/em&gt;, &lt;em&gt;#swagger&lt;/em&gt;, &lt;em&gt;#javadoc&lt;/em&gt;, &lt;em&gt;#junit&lt;/em&gt;, &lt;em&gt;#mockito&lt;/em&gt;, &lt;em&gt;#docker&lt;/em&gt;, &lt;em&gt;#jacoco&lt;/em&gt;, &lt;em&gt;#github actions&lt;/em&gt;, &lt;em&gt;#ci-cd&lt;/em&gt;, &lt;em&gt;#sonarqube&lt;/em&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Recientemente he cursado una formación con Adecco, y este es mi proyecto fin de estudios, que ha consistido en desarrollar una aplicación que permita gestionar recursos TIC y listas de recursos, para realizar los tests correspondientes, aplicando los conocimientos aprendidos, y que ha sido desplegada en el servicio de Railway.com.&lt;/p&gt;
&lt;h2 id=&quot;el-proyecto&quot;&gt;El proyecto&lt;/h2&gt;
&lt;p&gt;La plataforma, que está basada en &lt;strong&gt;Java&lt;/strong&gt; y &lt;strong&gt;Spring Boot&lt;/strong&gt;, utiliza un patrón Modelo-Vista-Controlador y una arquitectura cliente-servidor, haciendo uso del IDE &lt;strong&gt;IntelliJ IDEA&lt;/strong&gt;, de &lt;strong&gt;Maven&lt;/strong&gt; para la gestión del proyecto, de &lt;strong&gt;Git&lt;/strong&gt; y &lt;strong&gt;GitHub&lt;/strong&gt; para el versionado de código, de &lt;strong&gt;MySQL&lt;/strong&gt;, &lt;strong&gt;H2&lt;/strong&gt; y el ORM &lt;strong&gt;Hibernate&lt;/strong&gt; para la gestión de la base de datos y de una &lt;strong&gt;configuración LAMP dockerizada&lt;/strong&gt; para las pruebas.&lt;/p&gt;
&lt;p&gt;Para el frontend se ha empleado el gestor de plantillas &lt;strong&gt;Tymeleaft&lt;/strong&gt; y &lt;strong&gt;Bootstrap&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Para los tests se ha usado &lt;strong&gt;JUnit&lt;/strong&gt;, &lt;strong&gt;Mockito&lt;/strong&gt;, &lt;strong&gt;Selenium&lt;/strong&gt;. la API se ha probado con &lt;strong&gt;Swagger&lt;/strong&gt; y las estadísticas se han generado con &lt;strong&gt;JaCoCo&lt;/strong&gt; y &lt;strong&gt;SonarQube&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Para el despliegue se utilizaron tecnologías como &lt;strong&gt;Docker&lt;/strong&gt; y metodologías &lt;strong&gt;CI/CD&lt;/strong&gt; con &lt;strong&gt;GitHub Actions&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La planificación y codificación se han llevado a cabo usando &lt;strong&gt;Trello&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://recursos-tic.up.railway.app&quot;&gt;&lt;button&gt;Ver Recursos TIC en línea&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;destacados&quot;&gt;Destacados&lt;/h2&gt;
&lt;p&gt;Además de los requisitos del MVP, se han incluido las siguientes funcionalidades:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Diseño responsive, “mobile first”&lt;/li&gt;
&lt;li&gt;Web accesible AA. Testada con WAVE&lt;/li&gt;
&lt;li&gt;Seguridad por diseño&lt;/li&gt;
&lt;li&gt;Confirmaciones de borrado&lt;/li&gt;
&lt;li&gt;Implementación de login de usuarios&lt;/li&gt;
&lt;li&gt;Integra el editor TinyMCE&lt;/li&gt;
&lt;li&gt;Provee API REST e interfaz Swagger&lt;/li&gt;
&lt;li&gt;Incluye aviso legal, privacidad y cookies&lt;/li&gt;
&lt;li&gt;Documentación la aplicación con JavaDoc&lt;/li&gt;
&lt;li&gt;Usa el protocolo OpenGraph para RR.SS.&lt;/li&gt;
&lt;li&gt;Manifest para móviles (PWA)&lt;/li&gt;
&lt;li&gt;Desarrollada con Linux + Docker LAMP&lt;/li&gt;
&lt;li&gt;Despliegue&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;video&quot;&gt;Video&lt;/h1&gt;
&lt;p&gt;El proyecto fue presentado a empresas de tecnología, y se puede ver en el vídeo de la presentación del proyecto aquí:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/d_SeaUuKrMg&quot;&gt;&lt;button&gt;Video de la presentación&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;indicaciones-de-uso&quot;&gt;Indicaciones de uso&lt;/h1&gt;
&lt;h2 id=&quot;requisitos&quot;&gt;Requisitos&lt;/h2&gt;
&lt;p&gt;Para ejecutar el proyecto se requiere:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java 23 o superior&lt;/li&gt;
&lt;li&gt;Maven&lt;/li&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;configuración&quot;&gt;Configuración&lt;/h2&gt;
&lt;p&gt;Actualmente la aplicación se ejecuta localmente en el puerto 8082.&lt;/p&gt;
&lt;p&gt;Puede construirse un contenedor Docker con la imagen de la aplicación ejecutando el fichero &lt;code&gt;docker.sh&lt;/code&gt; que hace uso de docker-compose para lanzar la aplicación y la BBDD que requiere.&lt;/p&gt;
&lt;p&gt;Para generar un informe de cobertura de testing, se puede ejecutar el comando &lt;code&gt;mvn site&lt;/code&gt; y acceder a él en el directorio &lt;code&gt;target/site/jacoco/index.html&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;autores&quot;&gt;Autores&lt;/h1&gt;
&lt;p&gt;Desarrollado por &lt;a href=&quot;https://github.com/JavGuerra&quot;&gt;Javier&lt;/a&gt; y &lt;a href=&quot;https://github.com/kevinzamoraa&quot;&gt;Kevin&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;licencia&quot;&gt;Licencia&lt;/h2&gt;
&lt;p&gt;Sobre el código fuente: GNU GENERAL PUBLIC LICENSE Version 3&lt;/p&gt;
&lt;h2 id=&quot;enlaces&quot;&gt;Enlaces&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JavGuerra/recursos-tic-testing/refs/heads/main/src/main/resources/static/img/qr.svg&quot; alt=&quot;QR enlace a la Aplicación&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://recursos-tic.up.railway.app&quot;&gt;Aplicación&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://recursos-tic.up.railway.app/swagger-ui/index.html&quot;&gt;API REST&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/JavGuerra/recursos-tic-testing&quot;&gt;Repositorio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://youtu.be/d_SeaUuKrMg&quot;&gt;Ver el vídeo de la presentación del proyecto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://recursos-tic.up.railway.app/doc/presentacion-recursos_tic.pdf&quot;&gt;Ver el PDF de la presentación&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://javguerra.github.io/blog/loader-thymeleaft/&quot;&gt;Spinner loader en Thymeleaft&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><enclosure url="https://javguerra.github.io/_astro/recursos-tic.DMmpqNPg_ZqU5V8.webp"/><category>portfolio</category><category>web</category><category>java</category><category>spring boot</category><category>bootstrap</category><category>thymeleaft</category><category>spring security</category><category>accesibilidad</category><category>responsive</category><category>selenium</category><category>api</category><category>swagger</category><category>javadoc</category><category>junit</category><category>mockito</category><category>docker</category><category>jacoco</category><category>github actions</category><category>ci-cd</category><category>sonarqube</category><author>JavGuerra</author></item></channel></rss>