[Java] [Introduction to Spring Boot] Authentication function with Spring Security

6 minute read

Purpose

For those who have finished working on the Spring Quickstart Guide, those who have started learning Spring Boot, and those who want to review it.

We will share what we have learned by actually working on the official guide Securing a Web Application.

Check the completed form.
There is a top page, click here,
スクリーンショット 2020-07-13 11.59.12.png

Go to the login page. Enter the username and password for the test user and click the Sign in button
スクリーンショット 2020-07-13 11.59.27.png

You will be taken to a page that can only be viewed by authenticated people. You cannot access this screen if you are not logged in.
スクリーンショット 2020-07-13 12.00.36.png

The development environment and the review so far are as follows.

Development environment


OS: macOS Mojave version 10.14.6
Text editor: Visual Studio Code (hereinafter VSCode)
Java: 11.0.2

QuickstartGuide
Building a RESTful Web Service
Consuming a RESTful Web Service
Accessing Data with JPA
Handling Form Submission
Securing a Web Application

1. Start the Spring Boot project!

First, access spring initializr.

  1. Click the ADD DEPENDENCIES button to add Spring Web and Thymeleaf.
    2.Artifact, Name changed to securing-web.
  2. Change Java to 11.

Then click the GENERATE button to download the Zip file.

スクリーンショット 2020-07-13 13.17.09.png

Extract the downloaded Zip file and you’re ready to go.

2. Add code!

Open the previous folder with VS Code.
We recommend installing the Java Extension Pack for extensions. It is said that you should install it.

スクリーンショット 2020-06-30 10.08.25.png

Let’s create home.html!

Create a home.html file in src / main / resources / templates /.

スクリーンショット 2020-07-13 13.29.09.png

Add the code referring to the formula. It will be the top page.

home.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
      xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
  <head>
    <title>Spring Security Example</title>
  </head>
  <body>
    <h1>Welcome!</h1>

    <p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
  </body>
</html>

The html tag part is for writing th: 〇〇 and sec: 〇〇 (the description method using thymeleaf and Spring Security tags becomes possible).

Now let’s dig deeper into the description of thymeleaf in the added code.

thymeleaf is a template engine that can be handled by springboot. Described as th: 〇〇.
[Thymeleaf tutorial] written in Japanese (https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html#thymeleaf%E3%81%AE%E7%B4%B9%E4%BB% There is also 8B)!

th:href

This tag is set in the href attribute of the a tag. The description method is th: href =" @ {} ".
Specify the path in {}. This time it is / hello, so if you click the tag, it will transition to http: // localhost: 8080 / hello.

Let’s create hello.html!

Create a hello.html file in src / main / resources / templates /.

スクリーンショット 2020-07-13 14.21.54.png

Add the code referring to the formula.

hello.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
      xmlns:sec="https://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="Sign Out"/>
    </form>
  </body>
</html>

th: inline is for expanding the value of a variable in the text of the tag. Enclose the variable you want to display in [[...]].
This time, it is $ {# httpServletRequest.remoteUser}, so the name of the authenticated user is displayed.

When the Sign Out button is pressed, you will be redirected to / login? Logout.

Let’s create MvcConfig.java!

Create an MvcConfig.java file in src / main / java / com / example / securingweb /.

スクリーンショット 2020-07-13 14.43.27.png

Add the code referring to the formula.

MvcConfig.java


package com.example.securingweb;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfig implements WebMvcConfigurer {

  public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/home").setViewName("home");
    registry.addViewController("/").setViewName("home");
    registry.addViewController("/hello").setViewName("hello");
    registry.addViewController("/login").setViewName("login");
  }

}

The ** @ Configuration ** annotation is added to the class so that various Spring settings can be performed in Java code. (Setting class)
I have created an MvcConfig class that implements the WebMvcConfigurer interface and overrides the addViewControllers method.

registry.addViewController(“/home”).setViewName(“home”);

Instead of having another Controller and using the @GetMapping annotation to return the View name
By the above description

When the URL is http: // localhost: 8080 / home, the template ** home.html ** will be referenced.
It seems that the URL and template are mapped.
Login.html will be implemented later.

Add Spring Security to pom.xml!

Add the following to pom.xml to use Spring Security.

Spring Security is a framework for adding security features to web applications.
Provides comprehensive support for authentication, authorization, and protection against common abuse.

pom.xml


<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
		
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-test</artifactId>
  <scope>test</scope>
</dependency>

スクリーンショット_2020-07-13_15_32_20.png

Let’s create WebSecurityConfig.java!

Create a WebSecurityConfig.java file in src / main / java / com / example / securingweb /.

スクリーンショット 2020-07-13 15.48.47.png

Add the code referring to the formula.

WebSecurityConfig.java


package com.example.securingweb;

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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;


@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
        .antMatchers("/", "/home").permitAll()
        .anyRequest().authenticated()
        .and()
      .formLogin()
        .loginPage("/login")
        .permitAll()
        .and()
      .logout()
        .permitAll();
  }

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

    String password = passwordEncoder().encode("password");

    auth.inMemoryAuthentication()
        .passwordEncoder(passwordEncoder())
        .withUser("user").password(password).roles("USER");
  }

  @Bean
  public PasswordEncoder passwordEncoder() {
      return new BCryptPasswordEncoder();
  }

}

We will dig deeper into the added code.

① Inheritance of @EnableWebSecurity and WebSecurityConfigurerAdapter classes

WebSecurityConfig.java


@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  //abridgement
}

Spring Security is enabled by adding the @EnableWebSecurity annotation.
And it inherits an abstract class called WebSecurityConfigurerAdapter. Override the ** configure method ** in this class
We will implement whether or not to restrict page access.

② Set page access restrictions

WebSecurityConfig.java


@Override
protected void configure(HttpSecurity http) throws Exception {
  http
    .authorizeRequests()
      .antMatchers("/", "/home").permitAll() //URLs that do not require access restrictions
      .anyRequest().authenticated()  //Other URLs require authentication. You cannot access it unless you are authenticated
      .and()
    .formLogin()
      .loginPage("/login") //No access restrictions on the login screen
      .permitAll() //No authentication required
      .and()
    .logout()
      .permitAll(); //No authentication required
}

Overriding ** configure method **.
HttpSecurity is received as an argument, and it is a method for describing the settings for the part related to http request.
Set whether authentication is required when logging in, logging out, or accessing other pages.

③ User settings to authenticate

The implementation of this part has been said to be deprecated if you follow the official guide.
So it has a slightly different implementation.

WebSecurityConfig.java



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

//Encode password
String password = passwordEncoder().encode("password");

//Settings for in-memory authentication
auth.inMemoryAuthentication()
    .passwordEncoder(passwordEncoder())
    .withUser("user").password(password).roles("USER");
}

@Bean
public PasswordEncoder passwordEncoder() {
  return new BCryptPasswordEncoder();
}

** PasswordEncoder passwordEncoder () ** defines a method for hashing passwords.
Then, the password of the string is hashed with String password = passwordEncoder (). Encode ("password"); .

AuthenticationManagerBuilder is a class that enables in-memory authentication.

python


//Settings for in-memory authentication
auth.inMemoryAuthentication()
    .passwordEncoder(passwordEncoder())
    .withUser("user").password(password).roles("USER");
}

We implement it here and set the user to authenticate.

Let’s create login.html!

Create a login.html file in src / main / resources / templates /.

スクリーンショット 2020-07-14 10.45.45.png

Add the code referring to the formula. It will be the login page.

login.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
      xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
  <head>
    <title>Spring Security Example </title>
  </head>
  <body>
    <div th:if="${param.error}">
      Invalid username and password.
    </div>
    <div th:if="${param.logout}">
      You have been logged out.
    </div>
      <form th:action="@{/login}" method="post">
        <div><label> User Name : <input type="text" name="username"/> </label></div>
        <div><label> Password: <input type="password" name="password"/> </label></div>
        <div><input type="submit" value="Sign In"/></div>
      </form>
  </body>
</html>

There is a field to enter the User Name and Password.
th: if =" $ {param.error} is the area displayed when user authentication fails.
th: if =" $ {param.logout} is the area that will be displayed when you sign out (displayed after the Sign Out button is pressed in hello.html).

3. Let’s run it!

Now that the application is ready to run, let’s check.

Enter the following command in the terminal and press Enter.

Terminal


$ ./mvnw spring-boot:run

The top page is displayed.

スクリーンショット 2020-07-14 13.34.37.png

Click here to go to the login page.
スクリーンショット 2020-07-14 13.34.52.png

Enter an appropriate User Name and Password and press the Sign In button.
スクリーンショット 2020-07-14 13.37.30.png

The login page is redisplayed and the error message is also displayed.
Next, enter ʻuser in Uesr Name and password` in Password and press the Sign In button.

スクリーンショット 2020-07-14 13.39.23.png

I was able to transition to a page that can only be viewed by authenticated people.
スクリーンショット 2020-07-14 13.39.23.png

When you press the Sign Out button,

スクリーンショット 2020-07-14 13.41.36.png

You’ll be redirected to the login page and you’ll see a message.

Thank you for your hard work. done!

Reference site

** Deprecated alternative to User.withDefaultPasswordEncoder () **
** [Spring Security has started] # 2 User Authentication **
** “Hello World!” With Spring Security **