LoginSignup
1
1

More than 3 years have passed since last update.

Visual Studio CodeによるSpring5 MVC Webアプリ開発 Spring Security使用編 2/3【ページ作成編 1/2】

Posted at

はじめに

こちらからの続きです。
今回はログインページ、管理ユーザー作成ページを作成していきます。

form作成

ログインページ、ユーザー作成ページで使用するformを作成します。

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作成

ユーザー登録に関すビジネスロジックを作成します。

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("管理者");
        userInfo.setSectionNameJP("管理者");
        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;
    }
}

controller作成

ログインページ、管理ユーザー作成ページのcontrollerを作成します。

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) {
        //ADMINロールユーザーは1つのみ
        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";
    }
}

RootController.javaの変更

ルートにアクセスがあった際のリダイレクト先を認証画面に設定します。

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作成

ログインページ、管理ユーザー作成ページのviewを作成します。

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

テンプレートフラグメントを使って共通部分を部品化します。

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ヘッダ -->
<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>管理者ID登録ページ完了</title>
</head>
<body>
    <h1>管理者ID登録しました。</h1>
    <a th:href="@{/auth/login}">トップ</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>管理者ID登録ページ</title>
</head>
<body>
    <h1>管理者ID登録ページ</h1>

    <form method="post" action="#" th:action="@{index}" th:object="${authForm}">
        <div th:if="${signupDone}">
            <em>登録しました。</em>
        </div>

        <div th:if="${signupError}">
            <em>登録出来ませんでした。</em>
        </div>

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

        <div>
            <label for="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">登録</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>管理者ID登録ページ</title>
</head>
<body>
    <h1>管理者ID登録済みです。</h1>
    <a th:href="@{/auth/login}">トップ</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>申し訳ございません。エラーが発生しました。</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>ログインページ</title>
</head>
<body>
    <h1>ログインページ</h1>

    <form method="post" action="#" th:action="@{/login}">
        <div th:if="${loginError}">
            <em>ログイン出来ませんでした。ログインID、パスワードを確認して下さい。</em>
        </div>

        <div>
            <label for="uername">ログインID</label>:
            <input type="text" id="username" name="username" autofocus="autofocus">
        </div>

        <div>
            <label for="password">パスワード</label>:
            <input type="password" id="password" name="password">
        </div>

        <div>
            <button type="submit">ログイン</button>
        </div>
    </form>
</body>
</html>

まとめ

ここまで作りますと、動作確認が出来るようになります。
コンパイルして動かしてみて下さい。
管理ユーザーの登録が出来る様になります。

次はユーザー作成ページを作成します。
それで完成です。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1