Spring5 MVC Web application development with Visual Studio Code Spring Security usage 2/3 [Page creation 1/2]

Introduction

It is a continuation from here. This time, we will create a login page and an administrative user creation page.

form creation

Create a form to be used on the login page and user creation page.

D:\JAVA\Project\securitySample\src\main\java\com\example
└─form
  └─AuthForm.java

AuthForm.java

AuthForm.java


package com.example.web.form;

import javax.validation.constraints.Size;

import lombok.Data;

@Data
public class AuthForm {
    private String userId;

    @Size(min=3, max=255)
    private String password;

    private String userNameJP;
    private String sectionNameJP;
    private Boolean enabled;

    private String[] authority;
}

service creation

Create business logic related to user registration.

D:\JAVA\Project\securitySample\src\main\java\com\example
└─service
  ├─AuthService.java
  └─AuthServiceImpl.java

AuthService.java

AuthService.java


package com.example.service;

import java.util.List;

import com.example.persistence.entity.UserInfo;
import com.example.web.form.AuthForm;

public interface AuthService {
	void insertAdmin(AuthForm authForm);

	void insertUser(AuthForm authForm);

	void updateUser(AuthForm authForm);

	void deleteUser(String id);

	Integer adminCheck();

	List<UserInfo> findUserAll();

	AuthForm userRegById(String id);

}

AuthServiceImpl.java

AuthServiceImpl.java


package com.example.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.example.persistence.entity.UserInfo;
import com.example.persistence.entity.UserRoles;
import com.example.persistence.repository.UserInfoRepository;
import com.example.persistence.repository.UserRolesRepository;
import com.example.web.form.AuthForm;

@Service
public class AuthServiceImpl implements AuthService {
	@Autowired
	UserInfoRepository userInfoRepository;

	@Autowired
	UserRolesRepository userRolesRepository;

	@Override
	@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
	public void insertAdmin(AuthForm authForm) {

		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

		UserInfo userInfo = new UserInfo();
		UserRoles userRoles = new UserRoles();
		List<UserRoles> userRokesList  = new  ArrayList<UserRoles>();

		userInfo.setUserId(authForm.getUserId());
		userInfo.setPassword(encoder.encode( authForm.getPassword() ));

		userInfo.setUserNameJP("Administrator");
		userInfo.setSectionNameJP("Administrator");
		userInfo.setEnabled(true);

		userRoles.setUserId(authForm.getUserId());
		userRoles.setAuthority("ROLE_ADMIN");
		userRokesList.add(userRoles);

		userInfo.setUserRolesList(userRokesList);

		userInfoRepository.insert(userInfo);

		userInfo.getUserRolesList().forEach(s -> {
			userRolesRepository.insert(s);
		});
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
	public void insertUser(AuthForm authForm) {

		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

		UserInfo userInfo = new UserInfo();

		userInfo.setUserId(authForm.getUserId());
		userInfo.setPassword(encoder.encode( authForm.getPassword() ));

		userInfo.setUserNameJP(authForm.getUserNameJP());
		userInfo.setSectionNameJP(authForm.getSectionNameJP());
		userInfo.setEnabled(true);

		userInfoRepository.insert(userInfo);

		List<String> authorityList = new ArrayList<String>(Arrays.asList(authForm.getAuthority()));
		authorityList.add("ROLE_USER");

		authorityList.forEach(s -> {
			UserRoles userRoles = new UserRoles();
			userRoles.setUserId(authForm.getUserId());
			userRoles.setAuthority(s);

			userRolesRepository.insert(userRoles);
		});
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public Integer adminCheck() {
		return userRolesRepository.adminCheck();
	}


	@Override
	@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
	public void updateUser(AuthForm authForm){
		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

		UserInfo userInfo = new UserInfo();

		userInfo.setUserId(authForm.getUserId());
		userInfo.setPassword(encoder.encode(authForm.getPassword()));
		userInfo.setUserNameJP(authForm.getUserNameJP());
		userInfo.setSectionNameJP(authForm.getSectionNameJP());
		userInfo.setEnabled(authForm.getEnabled());

		userInfoRepository.update(userInfo);

		userRolesRepository.delete(authForm.getUserId());

		List<String> authorityList = new ArrayList<String>(Arrays.asList(authForm.getAuthority()));
		authorityList.add("ROLE_USER");

		authorityList.forEach(s -> {
			UserRoles userRoles = new UserRoles();
			userRoles.setUserId(authForm.getUserId());
			userRoles.setAuthority(s);

			userRolesRepository.insert(userRoles);
		});
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
	public void deleteUser(String id) {
		userInfoRepository.delete(id);
		userRolesRepository.delete(id);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public List<UserInfo> findUserAll() {
		return userInfoRepository.findUserAll();
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
	public AuthForm userRegById(String id){
		AuthForm authForm = new AuthForm();

		Optional<UserInfo> userInfoOpt = userInfoRepository.selectDetailByUserId(id);

		userInfoOpt.ifPresentOrElse(userInfo -> {
			authForm.setUserId(userInfo.getUserId());
			authForm.setPassword(userInfo.getPassword());
			authForm.setUserNameJP(userInfo.getUserNameJP());
			authForm.setSectionNameJP(userInfo.getSectionNameJP());
			authForm.setEnabled(userInfo.getEnabled());

			String[] arrayAuthority = new String[userInfo.getUserRolesList().size()];

			Integer i = 0;
			for (UserRoles ur : userInfo.getUserRolesList()) {
				arrayAuthority[i] = ur.getAuthority();
				i++;
			}

			authForm.setAuthority(arrayAuthority);
		},null);

		return authForm;
	}
}

Create controller

Create a controller for the login page and admin user creation page.

D:\JAVA\Project\securitySample\src\main\java\com\example
└─controller
  ├─AuthController.java
  └─AdminRegController.java

AuthController.java

AuthController.java


package com.example.web.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.example.service.AuthService;

@Controller
@RequestMapping("/auth")
public class AuthController {
	@Autowired
	AuthService authService;

	@GetMapping("/login")
    public String loginGet(Model model) {

		if(authService.adminCheck() <= 0) {
        	return "redirect:/adminReg/index";
        }
		return "auth/login";
    }

	@GetMapping("/403")
    public String index403(Model model) {
		return "auth/403";
    }

	@GetMapping("/login-error")
    public String loginErrorGet(Model model) {
        model.addAttribute("loginError", true);
        return "auth/login";
    }
}

AdminRegController.java

AdminRegController.java


package com.example.web.controller;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.example.service.AuthService;
import com.example.web.form.AuthForm;

@Controller
@RequestMapping("/adminReg")
public class AdminRegController {
	@Autowired
	AuthService authService;

	@GetMapping("/index")
    public String indexGet(Model model) {
		//Only one ADMIN role user
        if(authService.adminCheck() > 0) {
        	return "redirect:registered";
        }

		model.addAttribute("authForm", new AuthForm());
        return "adminReg/index";
    }

	@PostMapping("/index")
    public String indexPost(Model model,
    		@Valid AuthForm authForm, BindingResult bindingResult, HttpServletRequest request) {
        if (bindingResult.hasErrors()) {
        	model.addAttribute("signupError", true);
            return "adminReg/index";
        }

        try {
        	authService.insertAdmin(authForm);
        } catch (DataIntegrityViolationException e) {
            model.addAttribute("signupError", true);
            return "adminReg/index";
        }
        return "adminReg/done";
    }

	@GetMapping("/registered")
    public String registered(Model model) {
        return "adminReg/registered";
    }
}

Modification of RootController.java

Set the redirect destination on the authentication screen when the route is accessed.

RootController.java


package com.example.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class RootController {
    @GetMapping("/")
    public String root() {
        return "redirect:auth/login";
    }
}

view creation

Create a view of the login page and admin user creation page.

D:\JAVA\Project\securitySample\src\main\webapp\WEB-INF\templates
├─adminReg
| ├─done.html
| ├─index.html
| └─registered.html
├─auth
| ├─403.html
| └─login.html
└─fragment
  └─frag01.html

Use template fragments to componentize common parts.

fragment/frag01.html

frag01.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org"
	xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<!--HTML header-->
<head th:fragment="htmlhead" th:remove="tag">
	<meta charset="UTF-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
</body>
</html>

adminReg/done.html

done.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org"
	xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
	<head th:include="fragment/frag01 :: htmlhead"></head>
	<title>Administrator ID registration page completed</title>
</head>
<body>
	<h1>I registered the administrator ID.</h1>
	<a th:href="@{/auth/login}">Top</a>
</body>
</html>

adminReg/index.html

index.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org"
	xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
	<head th:insert="fragment/frag01 :: htmlhead"></head>
	<title>Administrator ID registration page</title>
</head>
<body>
	<h1>Administrator ID registration page</h1>

	<form method="post" action="#" th:action="@{index}" th:object="${authForm}">
		<div th:if="${signupDone}">
			<em>Has registered.</em>
		</div>

		<div th:if="${signupError}">
			<em>I couldn't register.</em>
		</div>

		<div>
			<label for="userId">Login ID</label>:
			<input type="text" autofocus="autofocus" th:field="*{userId}">
		</div>

		<div>
			<label for="password">password</label>:
			<input type="password" th:field="*{password}">
			<em th:if="${#fields.hasErrors('password')}" th:errors="*{password}">Password Error</em>
		</div>

		<div>
			<button type="submit">Registration</button>
		</div>
	</form>
</body>
</html>

adminReg/registered.html

registered.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org"
	xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
	<head th:insert="fragment/frag01 :: htmlhead"></head>
	<title>Administrator ID registration page</title>
</head>
<body>
	<h1>The administrator ID has been registered.</h1>
	<a th:href="@{/auth/login}">Top</a>
</body>
</html>

auth/403.html

403.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org" th:with="lang=${#locale.language}" th:lang="${lang}"
	xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
	<head th:insert="fragment/frag01 :: htmlhead"></head>
	<title>Error page</title>
</head>
<body>
	<div>
		<h1>I'm sorry. An error has occurred.</h1>
	</div>
</body>
</html>

auth/login.html

login.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org"
	xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
	<head th:insert="fragment/frag01 :: htmlhead"></head>
	<title>Login page</title>
</head>
<body>
	<h1>Login page</h1>

	<form method="post" action="#" th:action="@{/login}">
		<div th:if="${loginError}">
			<em>I couldn't log in. Please check your login ID and password.</em>
		</div>

		<div>
	        <label for="uername">Login ID</label>:
	   		<input type="text" id="username" name="username" autofocus="autofocus">
		</div>

		<div>
	    	<label for="password">password</label>:
			<input type="password" id="password" name="password">
		</div>

		<div>
			<button type="submit">Login</button>
		</div>
	</form>
</body>
</html>

Summary

If you make it so far, you will be able to check the operation. Please compile and run it. You will be able to register as an administrative user.

Next, create a user-created page. That's it.

Recommended Posts

Spring5 MVC Web application development with Visual Studio Code Spring Security usage 2/3 [Page creation 1/2]
Spring5 MVC Web application development with Visual Studio Code Spring Security usage 3/3 [Page creation 2/2]
Spring5 MVC Web application development with Visual Studio Code Spring Security usage 1/3 [Preparation]
Spring5 MVC Web application development with Visual Studio Code Maven template creation
Spring5 MVC web application development with Visual Studio Code SQL Server connection
Spring Boot2 Web application development with Visual Studio Code Hello World creation
Spring Boot2 Web application development with Visual Studio Code SQL Server connection
Spring5 MVC Web application development with Visual Studio Code Environment construction (Installation of JDK11, Maven, Tomcat, Visual Studio Code)
Build WebAPP development environment with Java + Spring with Visual Studio Code
Start web application development with Spring Boot
Spring Security usage memo: Cooperation with Spring MVC and Boot
Build Java program development environment with Visual Studio Code
Java web application development environment construction with VS Code (struts2)
Use PlantUML with Visual Studio Code
Inquiry application creation with Spring Boot
Web application creation with Nodejs with Docker
A record of setting up a Java development environment with Visual Studio Code
Run WEB application with Spring Boot + Thymeleaf
Introduction to Java development environment & Spring Boot application created with VS Code
Experience .NET 5 with Docker and Visual Studio Code
[Jakarta EE 8 application development with Gradle] 2. Project creation
Getting started with Java programs using Visual Studio Code
Why can I develop Java with Visual Studio Code?
Roughly the flow of web application development with Rails.
Web application development memo with MVN, Tomcat, JSP / Servlet with VScode
The first WEB application with Spring Boot-Making a Pomodoro timer-
To receive an empty request with Spring Web MVC @RequestBody