Spring Boot Security | Login | Inicio de Sesion + MYSQL #1

Spring Boot Security Inicio de Sesión con MYSQL

Crearemos un inicio de sesión sencillo pero bonito como lo hicimos aqui, con un usuario con role “USER” y otro usuario “ADMIN”.

Para empezar deberás de saber como conectar tu aplicación con la base de datos MYSQL. Si no sabes como, puedes mirar mi tutorial donde lo explico. spring-boot-mysql.

Version Video.

En caso de que quieras ver el video donde programo este tutorial paso a paso aqui te lo dejo. sino solo sigue bajando.

Paso a Paso

Configurar Vista

  1. Crear un proyecto Spring Boot, con las respectivas dependencias.
    1. Web
    2. Thymeleaf
    3. Devtools
    4. JPA
    5. MYSQL
      Proyecto Login Dependencias
      Proyecto Login Dependencias
  2. Crear las paginas HTML para el inicio de sesión y el acceso por roles. El diseño de la pagina lo podrán ver Aqui, y el código lo pueden descargar de Aqui. Asegúrate de tener la estructura de archivos de la siguiente manera.
    Proyecto Login Estructura
    Proyecto Login Estructura
  3. menu.html: Codigo Fuente
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
          xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
        <head>
            <title>Hello World!</title>
        </head>
        <body>
            <h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
            <form th:action="@{/logout}" method="post">
                <input type="submit" value="Cerrar Sesion"/>
            </form>
            <h1><a th:href="@{/admin}"> admin</a> | <a th:href="@{/user}"> user</a></h1>
        </body>
    </html>

    admin.html

    <h1>Admin Yeah</h1>

    user.html

    <h1>User Yeah!</h1>
  4. Configura la conexión a la base de datos en el archivo application.properties: Codigo Fuente
    Proyecto Login Application Properties
    Proyecto Login Application Properties
  5. Crear el controlador que redirigirá los request http (En index.html asegúrate que en el form el method sea get y el action sea “/menu”):
    <form class="col-12" th:action="@{/menu}" method="get">

    Codigo Fuente

    Proyecto Login Controller
    Proyecto Login Controller
  6. Inicia la aplicación con http://localhost:8080/ y deberás de tener algo parecido a la primer imagen y cuando presiones el botón “Ingresar” tengas la segunda imagen. Si tienes problemas visualizando las imágenes o el estilo css, verifica que la imagen y el link del css tenga el tag th apropiadamente.
    Proyecto Login Index
    Proyecto Login Index

    Proyecto Login Map Site
    Proyecto Login Map Site

Asegurar la aplicación

  1. Agrega la dependencia de Spring Boot Security a tu pom.xml: Codigo Fuente
    <!-- Security -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <!-- *** -->
    1. El paso anterior habilita el componente de seguridad, pero hay que configurarlo. Crear la siguiente clase que hereda de WebSecurityConfigurerAdapter. Codigo Fuente
      <span class="token keyword">package</span> com<span class="token punctuation">.</span>cristianruizblog<span class="token punctuation">.</span>loginSecurity<span class="token punctuation">.</span>config<span class="token punctuation">;</span>
      
      <span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>Autowired<span class="token punctuation">;</span>
      <span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>Bean<span class="token punctuation">;</span>
      <span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>Configuration<span class="token punctuation">;</span>
      <span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>config<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>authentication<span class="token punctuation">.</span>builders<span class="token punctuation">.</span>AuthenticationManagerBuilder<span class="token punctuation">;</span>
      <span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>config<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>web<span class="token punctuation">.</span>builders<span class="token punctuation">.</span>HttpSecurity<span class="token punctuation">;</span>
      <span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>config<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>web<span class="token punctuation">.</span>configuration<span class="token punctuation">.</span>EnableWebSecurity<span class="token punctuation">;</span>
      <span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>config<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>web<span class="token punctuation">.</span>configuration<span class="token punctuation">.</span>WebSecurityConfigurerAdapter<span class="token punctuation">;</span>
      <span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>crypto<span class="token punctuation">.</span>bcrypt<span class="token punctuation">.</span>BCryptPasswordEncoder<span class="token punctuation">;</span>
      
      <span class="token keyword">import</span> com<span class="token punctuation">.</span>cristianruizblog<span class="token punctuation">.</span>loginSecurity<span class="token punctuation">.</span>service<span class="token punctuation">.</span>UserDetailsServiceImpl<span class="token punctuation">;</span>
      
      <span class="token annotation punctuation">@Configuration</span>
      <span class="token annotation punctuation">@EnableWebSecurity</span>
      <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WebSecurityConfig</span> <span class="token keyword">extends</span> <span class="token class-name">WebSecurityConfigurerAdapter</span><span class="token punctuation">{</span>
      
          <span class="token comment">//Necesario para evitar que la seguridad se aplique a los resources</span>
          <span class="token comment">//Como los css, imagenes y javascripts</span>
          String<span class="token punctuation">[</span><span class="token punctuation">]</span> resources <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">{</span>
                  <span class="token string">"/include/**"</span><span class="token punctuation">,</span><span class="token string">"/css/**"</span><span class="token punctuation">,</span><span class="token string">"/icons/**"</span><span class="token punctuation">,</span><span class="token string">"/img/**"</span><span class="token punctuation">,</span><span class="token string">"/js/**"</span><span class="token punctuation">,</span><span class="token string">"/layer/**"</span>
          <span class="token punctuation">}</span><span class="token punctuation">;</span>
      	
          <span class="token annotation punctuation">@Override</span>
          <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">configure</span><span class="token punctuation">(</span>HttpSecurity http<span class="token punctuation">)</span> <span class="token keyword">throws</span> Exception <span class="token punctuation">{</span>
              http
                  <span class="token punctuation">.</span><span class="token function">authorizeRequests</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      	        <span class="token punctuation">.</span><span class="token function">antMatchers</span><span class="token punctuation">(</span>resources<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">permitAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span>  
      	        <span class="token punctuation">.</span><span class="token function">antMatchers</span><span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">,</span><span class="token string">"/index"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">permitAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      	        <span class="token punctuation">.</span><span class="token function">antMatchers</span><span class="token punctuation">(</span><span class="token string">"/admin*"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">access</span><span class="token punctuation">(</span><span class="token string">"hasRole('ADMIN')"</span><span class="token punctuation">)</span>
      	        <span class="token punctuation">.</span><span class="token function">antMatchers</span><span class="token punctuation">(</span><span class="token string">"/user*"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">access</span><span class="token punctuation">(</span><span class="token string">"hasRole('USER') or hasRole('ADMIN')"</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">anyRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">authenticated</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">and</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                  <span class="token punctuation">.</span><span class="token function">formLogin</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">loginPage</span><span class="token punctuation">(</span><span class="token string">"/login"</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">permitAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">defaultSuccessUrl</span><span class="token punctuation">(</span><span class="token string">"/menu"</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">failureUrl</span><span class="token punctuation">(</span><span class="token string">"/login?error=true"</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">usernameParameter</span><span class="token punctuation">(</span><span class="token string">"username"</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">passwordParameter</span><span class="token punctuation">(</span><span class="token string">"password"</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">and</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                  <span class="token punctuation">.</span><span class="token function">logout</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">permitAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">logoutSuccessUrl</span><span class="token punctuation">(</span><span class="token string">"/login?logout"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span>
          BCryptPasswordEncoder bCryptPasswordEncoder<span class="token punctuation">;</span>
          <span class="token comment">//Crea el encriptador de contraseñas	</span>
          <span class="token annotation punctuation">@Bean</span>
          <span class="token keyword">public</span> BCryptPasswordEncoder <span class="token function">passwordEncoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      		bCryptPasswordEncoder <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BCryptPasswordEncoder</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment">//El numero 4 representa que tan fuerte quieres la encriptacion.</span>
      <span class="token comment">//Se puede en un rango entre 4 y 31. </span>
      <span class="token comment">//Si no pones un numero el programa utilizara uno aleatoriamente cada vez</span>
      <span class="token comment">//que inicies la aplicacion, por lo cual tus contrasenas encriptadas no funcionaran bien</span>
              <span class="token keyword">return</span> bCryptPasswordEncoder<span class="token punctuation">;</span>
          <span class="token punctuation">}</span>
      	
          <span class="token annotation punctuation">@Autowired</span>
          UserDetailsServiceImpl userDetailsService<span class="token punctuation">;</span>
      	
          <span class="token comment">//Registra el service para usuarios y el encriptador de contrasena</span>
          <span class="token annotation punctuation">@Autowired</span>
          <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">configureGlobal</span><span class="token punctuation">(</span>AuthenticationManagerBuilder auth<span class="token punctuation">)</span> <span class="token keyword">throws</span> Exception <span class="token punctuation">{</span> 
       
              <span class="token comment">// Setting Service to find User in the database.</span>
              <span class="token comment">// And Setting PassswordEncoder</span>
              auth<span class="token punctuation">.</span><span class="token function">userDetailsService</span><span class="token punctuation">(</span>userDetailsService<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">passwordEncoder</span><span class="token punctuation">(</span><span class="token function">passwordEncoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>     
          <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
      Java

      Primero que todo cuando copies esta clase te saldrá un error con el objeto UserDetailsServiceImpl el cual crearemos después de esta explicación.

      Como segundo te explicare la configuración implementada en el metodo configure:

    2. El metodo authorizeRequests() permite restringir y/o dar acceso request HTTP 
      1. antMatchers(): Lista de URL que corresponden a un RequestMapping como lo hacemos en los controladores.
      2. permitAll(): Especifica que estas URLs son accesibles por cualquiera.
      3. access(): permite el acceso cumpliendo la expresión, en este caso tenemos la expresion “hasRole()”. Donde verifica si el usuario tiene ese especifico Role.
      4. anyRequest(): Ya que la configuración es lineal poniendo este metodo al final interpreta los request a las URLs que no fueron descritos, y en conjunto con el metodo authenticated() permite y da acceso a cualquier usuario que este autenticado.
    3. El metodo fromLogin(). Permite personalizar el proceso de inicio de sesión
      1. loginPage(): indica la url de la pagina de inicio de sesión
      2. defaultSuccessUrl(): Indica a cual URL sera redirigido cuando el usuario inicie sesión.
      3. failureUrl(): Indica a cual URL sera redirigido cuando el inicio de sesión falla.
      4. usernameParameter()passwordParameter(): Indica el nombre de los parámetros respectivamente.
    4. El metodo logout(): Personaliza el proceso de cierre de sesión.
      1. logoutSuccessUrl(): Indica la URL donde sera redirigido cuando el usuario cierre sesión.

Capa de servicio y repositorio

  1. Empezaremos creando la siguiente estructura de archivos:
    Proyecto Login Estructura Completa
    Proyecto Login Estructura Completa
  2. Entidades | Entity: Siguiendo los lineamientos especificados por la documentación de Spring 5.2.0 Se necesitan dos tablas, una para Usuarios y otra para los Roles (Conocido como Authorities).Documentacion Oficial. Y esta es la implementacion con Spring JPA e Hibernate.
      1. Authority: Codigo Fuente
        <span class="token keyword">package</span> com<span class="token punctuation">.</span>cristianruizblog<span class="token punctuation">.</span>loginSecurity<span class="token punctuation">.</span>entity<span class="token punctuation">;</span>
        
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>Column<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>Entity<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>GeneratedValue<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>GenerationType<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>Id<span class="token punctuation">;</span>
        
        <span class="token annotation punctuation">@Entity</span>
        <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Authority</span> <span class="token punctuation">{</span>
        
        	<span class="token annotation punctuation">@Id</span>
        	<span class="token annotation punctuation">@GeneratedValue</span><span class="token punctuation">(</span>strategy<span class="token operator">=</span>GenerationType<span class="token punctuation">.</span>AUTO<span class="token punctuation">)</span>
        	<span class="token keyword">private</span> Long id<span class="token punctuation">;</span>
        	
        	<span class="token annotation punctuation">@Column</span>
        	<span class="token keyword">private</span> String authority<span class="token punctuation">;</span>
        	
        	<span class="token keyword">public</span> String <span class="token function">getAuthority</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        		<span class="token keyword">return</span> authority<span class="token punctuation">;</span>
        	<span class="token punctuation">}</span>
        
        	<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setAuthority</span><span class="token punctuation">(</span>String authority<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        		<span class="token keyword">this</span><span class="token punctuation">.</span>authority <span class="token operator">=</span> authority<span class="token punctuation">;</span>
        	<span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        Java

         

      2. User: Codigo Fuente
        <span class="token keyword">package</span> com<span class="token punctuation">.</span>cristianruizblog<span class="token punctuation">.</span>loginSecurity<span class="token punctuation">.</span>entity<span class="token punctuation">;</span>
        
        <span class="token keyword">import</span> java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>Set<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>Column<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>Entity<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>FetchType<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>GeneratedValue<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>GenerationType<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>Id<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>JoinColumn<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>JoinTable<span class="token punctuation">;</span>
        <span class="token keyword">import</span> javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span>ManyToMany<span class="token punctuation">;</span>
        
        <span class="token keyword">import</span> com<span class="token punctuation">.</span>cristianruizblog<span class="token punctuation">.</span>loginSecurity<span class="token punctuation">.</span>entity<span class="token punctuation">.</span>Authority<span class="token punctuation">;</span>
        
        <span class="token annotation punctuation">@Entity</span>
        <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
        
        <span class="token annotation punctuation">@Id</span>
        <span class="token annotation punctuation">@GeneratedValue</span><span class="token punctuation">(</span>strategy<span class="token operator">=</span>GenerationType<span class="token punctuation">.</span>AUTO<span class="token punctuation">)</span>
        <span class="token keyword">private</span> Long id<span class="token punctuation">;</span>
        
        <span class="token annotation punctuation">@Column</span>
        <span class="token keyword">private</span> String username<span class="token punctuation">;</span>
        
        <span class="token annotation punctuation">@Column</span>
        <span class="token keyword">private</span> String password<span class="token punctuation">;</span>
        
        <span class="token annotation punctuation">@Column</span>
        <span class="token keyword">private</span> <span class="token keyword">boolean</span> enabled<span class="token punctuation">;</span>
        
        <span class="token annotation punctuation">@ManyToMany</span><span class="token punctuation">(</span>fetch <span class="token operator">=</span> FetchType<span class="token punctuation">.</span>EAGER<span class="token punctuation">)</span>
        <span class="token annotation punctuation">@JoinTable</span><span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"authorities_users"</span><span class="token punctuation">,</span>
        joinColumns<span class="token operator">=</span><span class="token annotation punctuation">@JoinColumn</span><span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"usuario_id"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        inverseJoinColumns<span class="token operator">=</span><span class="token annotation punctuation">@JoinColumn</span><span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token string">"authority_id"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token keyword">private</span> Set<span class="token operator"><</span>Authority<span class="token operator">></span> authority<span class="token punctuation">;</span>
        
        <span class="token comment">//Getters y Setters</span>
        
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">final</span> <span class="token keyword">int</span> prime <span class="token operator">=</span> <span class="token number">31</span><span class="token punctuation">;</span>
            <span class="token keyword">int</span> result <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
            result <span class="token operator">=</span> prime <span class="token operator">*</span> result <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>id <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token operator">:</span>id<span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span> result<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">equals</span><span class="token punctuation">(</span>Object obj<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token operator">==</span> obj<span class="token punctuation">)</span>
                <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token operator">==</span> null<span class="token punctuation">)</span>
                <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> obj<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
            User other <span class="token operator">=</span> <span class="token punctuation">(</span>User<span class="token punctuation">)</span> obj<span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>id <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>other<span class="token punctuation">.</span>id <span class="token operator">!=</span> null<span class="token punctuation">)</span>
                    <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>id<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>other<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">)</span>
                    <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
                <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> String <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token string">"User [id="</span> <span class="token operator">+</span> id <span class="token operator">+</span> <span class="token string">", username="</span> <span class="token operator">+</span> username <span class="token operator">+</span> <span class="token string">", password="</span> <span class="token operator">+</span> password <span class="token operator">+</span> <span class="token string">"]"</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        
        <span class="token punctuation">}</span>
        Java
  3. Repositorios | Acceso a Datos: Por el momento tenemos una sola interface que hereda de CrudRepository y donde declaramos un metodo donde se busca por username. Si necesitas un poco mas de explicación acerca de esto puedes ver estos tutoriales. JPA Parte 1 y JPA Parte 2. Codigo Fuente
    <span class="token keyword">package</span> com<span class="token punctuation">.</span>cristianruizblog<span class="token punctuation">.</span>loginSecurity<span class="token punctuation">.</span>repository<span class="token punctuation">;</span>
    
    <span class="token keyword">import</span> java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>Optional<span class="token punctuation">;</span>
    <span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>repository<span class="token punctuation">.</span>CrudRepository<span class="token punctuation">;</span>
    <span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span>Repository<span class="token punctuation">;</span>
    <span class="token keyword">import</span> com<span class="token punctuation">.</span>cristianruizblog<span class="token punctuation">.</span>loginSecurity<span class="token punctuation">.</span>entity<span class="token punctuation">.</span>User<span class="token punctuation">;</span>
    
    <span class="token annotation punctuation">@Repository</span>
    <span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">UserRepository</span> <span class="token keyword">extends</span> <span class="token class-name">CrudRepository</span><span class="token operator"><</span>User<span class="token punctuation">,</span> Long<span class="token operator">></span>  <span class="token punctuation">{</span>
        <span class="token keyword">public</span> Optional<span class="token operator"><</span>User<span class="token operator">></span> <span class="token function">findByUsername</span><span class="token punctuation">(</span>String username<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    Java
  4. Service: Necesitaremos crear la implementacion para la interface UserDetailsService, la cual esta dentro de la dependencia de Spring Security Codigo Fuente
<span class="token keyword">package</span> com<span class="token punctuation">.</span>cristianruizblog<span class="token punctuation">.</span>loginSecurity<span class="token punctuation">.</span>service<span class="token punctuation">;</span>

<span class="token keyword">import</span> java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>ArrayList<span class="token punctuation">;</span>
<span class="token keyword">import</span> java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>List<span class="token punctuation">;</span>

<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>Autowired<span class="token punctuation">;</span>
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>core<span class="token punctuation">.</span>GrantedAuthority<span class="token punctuation">;</span>
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>core<span class="token punctuation">.</span>authority<span class="token punctuation">.</span>SimpleGrantedAuthority<span class="token punctuation">;</span>
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>core<span class="token punctuation">.</span>userdetails<span class="token punctuation">.</span>User<span class="token punctuation">;</span>
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>core<span class="token punctuation">.</span>userdetails<span class="token punctuation">.</span>UserDetails<span class="token punctuation">;</span>
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>core<span class="token punctuation">.</span>userdetails<span class="token punctuation">.</span>UserDetailsService<span class="token punctuation">;</span>
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>core<span class="token punctuation">.</span>userdetails<span class="token punctuation">.</span>UsernameNotFoundException<span class="token punctuation">;</span>
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span>Service<span class="token punctuation">;</span>

<span class="token keyword">import</span> com<span class="token punctuation">.</span>cristianruizblog<span class="token punctuation">.</span>loginSecurity<span class="token punctuation">.</span>entity<span class="token punctuation">.</span>Authority<span class="token punctuation">;</span>
<span class="token keyword">import</span> com<span class="token punctuation">.</span>cristianruizblog<span class="token punctuation">.</span>loginSecurity<span class="token punctuation">.</span>repository<span class="token punctuation">.</span>UserRepository<span class="token punctuation">;</span>

<span class="token annotation punctuation">@Service</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserDetailsServiceImpl</span> <span class="token keyword">implements</span> <span class="token class-name">UserDetailsService</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    UserRepository userRepository<span class="token punctuation">;</span>
	
    <span class="token annotation punctuation">@Override</span>
     <span class="token keyword">public</span> UserDetails <span class="token function">loadUserByUsername</span><span class="token punctuation">(</span>String username<span class="token punctuation">)</span> <span class="token keyword">throws</span> UsernameNotFoundException <span class="token punctuation">{</span>
		
     <span class="token comment">//Buscar el usuario con el repositorio y si no existe lanzar una exepcion</span>
     com<span class="token punctuation">.</span>cristianruizblog<span class="token punctuation">.</span>loginSecurity<span class="token punctuation">.</span>entity<span class="token punctuation">.</span>User appUser <span class="token operator">=</span> 
                 userRepository<span class="token punctuation">.</span><span class="token function">findByUsername</span><span class="token punctuation">(</span>username<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">orElseThrow</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token keyword">new</span> <span class="token class-name">UsernameNotFoundException</span><span class="token punctuation">(</span><span class="token string">"No existe usuario"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		
    <span class="token comment">//Mapear nuestra lista de Authority con la de spring security </span>
    List grantList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span>Authority authority<span class="token operator">:</span> appUser<span class="token punctuation">.</span><span class="token function">getAuthority</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// ROLE_USER, ROLE_ADMIN,..</span>
        GrantedAuthority grantedAuthority <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SimpleGrantedAuthority</span><span class="token punctuation">(</span>authority<span class="token punctuation">.</span><span class="token function">getAuthority</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            grantList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>grantedAuthority<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
		
    <span class="token comment">//Crear El objeto UserDetails que va a ir en sesion y retornarlo.</span>
    UserDetails user <span class="token operator">=</span> <span class="token punctuation">(</span>UserDetails<span class="token punctuation">)</span> <span class="token keyword">new</span> <span class="token class-name">User</span><span class="token punctuation">(</span>appUser<span class="token punctuation">.</span><span class="token function">getUsername</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> appUser<span class="token punctuation">.</span><span class="token function">getPassword</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> grantList<span class="token punctuation">)</span><span class="token punctuation">;</span>
         <span class="token keyword">return</span> user<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
Java

Crear usuarios.

Necesitaremos insertar datos en las tablas que tenemos en la base de datos. Empezaremos por crear los usuarios y las autoridades y luego asignaremos los cruzaremos.

Usuarios: Para poder crear un usuario necesitaremos la contraseña encriptada por lo cual crearemos la siguiente clase para simular el encriptador. Codigo Fuente

<span class="token keyword">package</span> com<span class="token punctuation">.</span>cristianruizblog<span class="token punctuation">.</span>loginSecurity<span class="token punctuation">.</span>util<span class="token punctuation">;</span>

<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>crypto<span class="token punctuation">.</span>bcrypt<span class="token punctuation">.</span>BCryptPasswordEncoder<span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Passgenerator</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        BCryptPasswordEncoder bCryptPasswordEncoder <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BCryptPasswordEncoder</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//El String que mandamos al metodo encode es el password que queremos encriptar.</span>
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>bCryptPasswordEncoder<span class="token punctuation">.</span><span class="token function">encode</span><span class="token punctuation">(</span><span class="token string">"1234"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
Java

Esta clase deberá de ejecutarse como aplicación Java, y la contraseña encriptada aparecerá en tu consola.

Ahora crearemos un usuario admin y user

Reemplaza la palabra password por lo que apareció en tu consola en el paso anterior<span class="token punctuation">.</span>

<span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> <span class="token keyword">user</span> <span class="token punctuation">(</span>id<span class="token punctuation">,</span>enabled<span class="token punctuation">,</span>password<span class="token punctuation">,</span>username<span class="token punctuation">)</span> 
<span class="token keyword">VALUES</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">0b1</span><span class="token punctuation">,</span><span class="token string">"password"</span><span class="token punctuation">,</span><span class="token string">"admin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> <span class="token keyword">user</span> <span class="token punctuation">(</span>id<span class="token punctuation">,</span>enabled<span class="token punctuation">,</span>password<span class="token punctuation">,</span>username<span class="token punctuation">)</span> 
<span class="token keyword">VALUES</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">0b1</span><span class="token punctuation">,</span><span class="token string">"password"</span><span class="token punctuation">,</span><span class="token string">"user"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> authority <span class="token punctuation">(</span>id<span class="token punctuation">,</span>authority<span class="token punctuation">)</span> <span class="token keyword">VALUES</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token string">"ROLE_ADMIN"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> authority <span class="token punctuation">(</span>id<span class="token punctuation">,</span>authority<span class="token punctuation">)</span> <span class="token keyword">VALUES</span> <span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token string">"ROLE_USER"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> authorities_users <span class="token punctuation">(</span>usuario_id<span class="token punctuation">,</span> authority_id<span class="token punctuation">)</span> <span class="token keyword">VALUES</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> authorities_users <span class="token punctuation">(</span>usuario_id<span class="token punctuation">,</span> authority_id<span class="token punctuation">)</span> <span class="token keyword">VALUES</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> authorities_users <span class="token punctuation">(</span>usuario_id<span class="token punctuation">,</span> authority_id<span class="token punctuation">)</span> <span class="token keyword">VALUES</span> <span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
SQL

PRECAUCION:

Hay que cambiar el index.html un poco. El action hay que apuntarlo a /login y el metodo debe ser post.

<form class="col-12" th:action="@{/login}" method="post">

Ya solo falta ejecutar la aplicación con ambos usuarios y verificar que con el usuario user no se puede acceder al link de admin

Bueno esto fue todo, no dudes en dejar tu comentario ademas puedes ver mi codigo completo en mi repositorio de github o ver este ejemplo en video. Muchas gracias por llegar al final del tutorial.

GitHub: https://github.com/cruizg93/SpringBoot-Security-MySql

@Cruizg93

8 Replies to “Spring Boot Security | Login | Inicio de Sesion + MYSQL #1”

    1. OK, no sabía que spring.jpa.hibernate.ddl-auto=create crea las tabla pero no la base de datos. Solo tenía que tener la base de datos ya creada. Gracias por el tutorial.

    2. INSERT INTO user (id, enabled, password, username)
      VALUES (1, TRUE, ‘$2a$04$GR0Lqg9.0KSqaGnOXxkXCOIe3mLumryflpMUgrJAOs1fq6zHBTf4q’, ‘admin’),
      (2, TRUE, ‘$2a$04$GR0Lqg9.0KSqaGnOXxkXCOIe3mLumryflpMUgrJAOs1fq6zHBTf4q’, ‘user’);

      INSERT INTO authority (id, authority)
      VALUES (1, ‘ROLE_ADMIN’),
      (2, ‘ROLE_USER’);

      INSERT INTO authorities_users (user_id, authority_id)
      VALUES (1, 1),
      (1, 2),
      (2, 2);
      — password

  1. Buenas tardes, felicidades por su valioso aporte. Como hago si quiero implementar spring security, pero solo a mi servicio rest. especificamente quiero proteger cada endpoint por separado, por medio de los roles. he leido sobre @PreAuthorize pero no logro entenderlo del todo..
    El front esta en angular.

  2. Buenas noches segui tu tutorial y esta bien explicado, solo que lo estaba haciendo con spring boot y oracle pero a la hora de iniciar session no me hace match el usuario y contraseña, no se si me puedes ayudar, en oracle no me deja crear la tabla user.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *