[Java] Try implementing the login function with Spring Boot

2 minute read

Continuing from the previous article [Automating migration with Spring Boot Flyway], we will implement the login process.

build.gradle

Add spring-boot-starter-security.

build.gradle



plugins {
    id'java'
    id'org.springframework.boot' version '2.3.1.BUILD-SNAPSHOT'
    id'io.spring.dependency-management' version '1.0.9.RELEASE'
    id'com.avast.gradle.docker-compose' version '0.12.1'
    id'org.flywaydb.flyway' version '6.4.3'
}

// ... omitted

dependencies {
    implementation'org.springframework.boot:spring-boot-starter-data-jdbc'
    implementation'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation'org.springframework.boot:spring-boot-starter-web'
    implementation'org.flywaydb:flyway-core'
    implementation "org.springframework.boot:spring-boot-starter-security" // add
    developmentOnly'org.springframework.boot:spring-boot-devtools'
    runtimeOnly'mysql:mysql-connector-java'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group:'org.junit.vintage', module:'junit-vintage-engine'
    }
    testImplementation'org.springframework.security:spring-security-test' // add
}

Create SecurityConfig.java

Create in the same hierarchy as Application.

SecurityConfig.java



package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.sql.DataSource;

// Security setting class
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    // password encoder
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
     }

    @Autowired
    private DataSource dataSource;

    // sql statement to get the user
    private static final String USER_SQL = "SELECT"
        + "email,"
        + "password,"
        + "true"
        + "FROM"
        + "users"
        + "WHERE"
        + "email = ?";

    // sql statement to get permission
    private static final String ROLE_SQL = "SELECT"
        + "email,"
        + "role"
        + "FROM"
        + "users"
        + "WHERE"
        + "email = ?";

    @Override
    public void configure(WebSecurity web) throws Exception {

        // Do not apply security to access static resources
        web.ignoring().antMatchers("/resources/**");
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // Set up a login-free page
        http.authorizeRequests()
            .antMatchers("/resources/**");
            // Access denied for other pages
            .anyRequest().authenticated();
        
        // Login form settings
        http.formLogin()
            // user parameter name
            .usernameParameter("email")
            // Password parameter name
            .passwordParameter("password");

        // disable CSRF measures
        http.csrf().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        // Get user information for login process from DB
        auth.jdbcAuthentication()
            .dataSource(dataSource)
            .usersByUsernameQuery(USER_SQL)
            .authoritiesByUsernameQuery(ROLE_SQL)
            .passwordEncoder(passwordEncoder());
    }
}

Modify R__1_insert_datas.sql

Change the password to an encoded string. The original string is passw0rd.

R__1_insert_datas.sql


INSERT INTO `users` VALUES
    (1,'Yamada','Hanako','[email protected]','$2a$06$hY5MzfruCds1t5uFLzrlBuw3HcrEGeysr9xJE4Cml5xEOVf425pmK',NULL,NOW(),NULL,NULL,NULL,NULL,1),
    (2,'Suzuki','Taro','[email protected]','$2a$06$hY5MzfruCds1t5uFLzrlBuw3HcrEGeysr9xJE4Cml5xEOVf425pmK',NULL,NOW(),NULL,NULL,NULL,NULL,1);

Application startup

If you have already started docker. Execute ./gradlew composeDown once and delete all containers.

$ ./gradlew composeDown


> Task :composeDown
Stopping todoDb ...
Stopping todoDb ... done
Removing todoDb ...
Removing todoDb ... done
Removing network eb415214cdb915cc9f956bc6e963ac23_spring-boot-todo-sample__default

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use'--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.4.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 4s
1 actionable task: 1 executed

Start docker again with ./gradlew composeUp and create a database.

Then start the application with ./graldew boot Run.Application.yml of previous article.

When you access the following URL, you will be redirected to /login. http://localhost:18082 ![Screenshot 2020-06-15 23.42.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631926/c4fb06e4-5ef7-d6c8-7fe6-(040288f43f98.png)

Since the page after login is not specified, a blank page will be displayed after login. Username: [email protected] or [email protected] Password: passw0rd

Next time, I will write about user registration and editing.