我想要创建一个登录界面

首先

Java没有像PHP的Laravel那样可以用一个命令创建登录功能模板的功能。如果只是要实现登录功能,可以在SpringBoot的Spring Security项目中引入,这样就可以提供具有固定用户名和密码的登录功能。但是,为了与数据库进行协作,需要一些相关知识。因此,在利用chatGPT(GPT4)创建登录功能时,我将记录这篇文章作为备忘录。

关于环境

    • Javaのバージョン: 17

 

    • Spring Bootのバージョン: 2.5.4

 

    • MacOS

 

    Eclipse(IDE)

ChatGPT的知識基于2021年9月之前的信息,因此它在那个时刻执行的是最新版本的工作。

关于如何在Java中实现登录功能

在Java的框架(Spring Boot)中,有一个名为Spring Security的功能,它可以通过简单地将其引入项目来为项目添加登录功能。

スクリーンショット 2023-07-14 14.48.59.png
https___qiita-image-store.s3.ap-northeast-1.amazonaws.jpeg

引进Spring Security的方法

在多种方式中选择一种SpringBoot的引入方法。

如果要创建新项目。

在使用Eclipse创建新项目时,只需勾选依赖关系,Spring Security将自动设置项目的依赖关系。

依赖关系是调用特定功能的设置。
Spring Boot最初就包含了连接数据库、设置安全性和创建Web应用程序的功能,想要调用这些功能就需要设置依赖关系。

スクリーンショット 2023-07-14 13.55.23.png

如果要添加到现有项目中

要在现有项目中添加Spring Security的依赖关系,需要编辑项目的构建工具(Maven或Gradle)的配置文件。
在创建项目时,Maven和Gradle会有一个被配置。
如果项目中存在build.gradle文件,则为Gradle;
如果存在pom.xml文件,则为Maven。

在使用Gradle的情况下

    1. 打开项目的构建文件(build.gradle)。

 

    1. 在dependencies部分中添加Spring Security的依赖关系。

 

    保存文件。
dependencies {
    // 他の依存関係の設定
    implementation 'org.springframework.boot:spring-boot-starter-security'
}

    1. 为了更新依存关系,执行构建工具。

 

    1. 在终端中切换到项目的根目录。

 

    执行以下命令。
gradle build

对于Maven

    1. 打开项目的pom.xml文件(如使用Maven)。

在部分内,添加Spring Security的依赖关系。请添加以下依赖关系的代码块。

<dependencies>
    <!-- 他の依存関係の設定 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
</dependencies>
    1. 请保存文件并更新依赖关系的构建工具。

在项目的根目录中执行以下命令。

mvn clean install

這將在項目中添加Spring Security的依賴關係。

关于登录信息(账户)

如果在使用Spring Security时已经达到可以显示HTML的阶段,那么当访问该URL时将会显示登录页面。然而,由于尚未与数据库进行协作,因此只能使用以下固定的帐户来登录。

    • user名:user

 

    パスワード:コンソールに表示されるランダムな文字列

密码需要通过哈希化的随机数显示在控制台上,因此需要将其复制并粘贴。

スクリーンショット 2023-07-14 15.15.38.png
スクリーンショット 2023-07-14 15.19.02.png

与数据库的连接

在SpringBoot中,可以通过与数据库连接来使用非固定账户,为此需要对项目和数据库进行各种准备工作。

关于桌子

通常登录界面所需的信息是用户名和密码,因此表格信息如下:

表名:用户

名前タイプidint(11)usernamevarchar(255)passwordvarchar(255)emailvarchar(255)

只要有用户名(username)和密码(password)存在,即使登录界面上还包含与之无关的电子邮件列(email),也不会有问题。

保存的数据需要进行哈希化。

正如下图所示,密码被转换为符号和数字的一系列字符。总之,Spring Security推荐将密码进行哈希处理后保存,数据库中存储的密码默认情况下是无法使用未经哈希处理的。

スクリーンショット 2023-07-14 12.09.37.png

简而言之,无法通过非红框以外的账号登录到图像帐户。
顺便提一下,红框中的密码是以root4和root5为关键字进行哈希处理的。关于如何进行哈希处理并保存的方法将在后面的说明中进行解释,但实际上是通过准备新账号创建界面并在那里创建帐户的方法。

密码哈希化由Spring Security执行

Spring Security 中有一个功能叫密码编码器,可以对密码进行转换,简化密码的哈希化和验证(匹配确认)等操作。哈希化是一种将密码加密并将原始密码转换为不可恢复形式的方法。

使用密码编码器需要

密码编码器是一个接口,它包含了实现具体哈希算法的方法,为了使用它,需要在项目中准备一个专门的类(有关代码等详细信息请参考后述)。

在试用登录功能之前

正如前面所述,为了测试使用Spring Security实现的登录功能,需要一个经过哈希处理的密码。因此,即使在数据库表中提前以明文保存了用户名和密码,也不能使用该账户进行登录。因此,为了测试登录功能,还需要实现账户的新建功能。

所需项目的最低文件

要使用Spring Security来执行登录功能和新建账户页面,需要以下一系列文件。

文件名和目录名没有规定,以下是一些常见的名称。

.
├── src
   ├── main
      ├── java
         ├── com
            ├── example
               ├── controller
                  ├── LoginController.java
                  └── RegisterController.java
               ├── model
                  ├── User.java
                  └── UserDto.java
               ├── service
                  ├── UserService.java
                  └── UserServiceImpl.java
               └── config
                   ├── SecurityConfig.java
                   └── PasswordEncoderConfig.java
      ├── resources
         ├── templates
            ├── login.html
            └── register.html
         └── application.properties
   ├── test
├── build.gradle (またはpom.xmlもしMavenを使用している場合)
└── ...

模型类 (User.java)

用于表示用户数据的类。根据情况,它也被称为实体类或数据传输对象(DTO)。在这里,例如,如果数据库中存在Users表,则可以创建一个名为User.java的文件,并准备一个变量来存储用户名和密码,从而将表与Java关联起来。

数据访问对象(UserRepository.java)

用于保存和检索用户数据的接口。可以使用Spring Data JPA来简化数据库操作。JPA是将表列和Java变量进行映射的功能。使用它需要像Spring Security一样配置依赖关系。

服务类 (UserService.java)

实现与用户相关的业务逻辑的类。例如,在此处创建新用户注册和现有用户搜索等处理。

控制器类(LoginController.java)

用于处理HTTP请求的类。处理登录和注册请求,显示适当的视图并执行相应的方法。

视图文件(login.html,register.html)

用于向用户显示登录表单和新用户注册表单的HTML模板。

安全配置类(SecurityConfig.java)

定义了Spring Security配置的类。设置登录机制、密码编码、授权规则等。

数据库连接设置

数据库连接信息(application.properties)

把与互联数据库相关的URL和端口号等信息,写在application.properties文件里。

スクリーンショット 2023-07-14 17.30.42.png

因此,连接设置如下所示。

# データベースに接続するためのURLを設定します。ここではMySQLのデータベース「LibraryManagementSystem」に接続するためのURLを指定しています。
spring.datasource.url=jdbc:mysql://localhost:8889/LibraryManagementSystem?useSSL=false&serverTimezone=UTC

# データベースに接続するためのユーザー名を設定します。ここでは'root'というユーザー名を指定しています。
spring.datasource.username=root

# データベースに接続するためのパスワードを設定します。ここでは'root'というパスワードを指定しています。
spring.datasource.password=root

# データベースに接続するためのドライバークラス名を設定します。ここではMySQL用のドライバーを指定しています。
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# データベースとエンティティの間のテーブル作成・更新・削除の動作を制御します。ここでは何もしないことを示す'none'を指定しています。
spring.jpa.hibernate.ddl-auto=none

# 実行されるSQLをログに出力するかどうかを制御します。ここでは出力するために'true'を指定しています。
spring.jpa.show-sql=true

# 使用するデータベースの種類に合わせたSQLを生成するための方言(Dialect)を指定します。ここではMySQL用の方言を指定しています。
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

# SQLをログに出力する際に整形するかどうかを制御します。ここでは整形するために'true'を指定しています。
spring.jpa.properties.hibernate.format_sql=true

# Springのログレベルを設定します。ここではDEBUGレベルのログを出力するように設定しています。
logging.level.org.springframework=DEBUG

不仅包括连接设置,还包括将SQL日志输出到控制台等设置,并不是所有的代码都是必需的。

文件位置(结构图)

    application.properties
project-directory               # プロジェクトのルートディレクトリ
├── src                         # ソースコードを格納するディレクトリ
│   ├── main                    # メインのソースコードとリソースを格納するディレクトリ
│   │   ├── java                # Javaソースコードを格納するディレクトリ
│   │   │   └── com             # ここからパッケージ構造が始まる
│   │   │       └── example     # 例えば 'com.example' パッケージ
│   │   │           └── ...     # その他のパッケージとJavaクラス
│   │   └── resources           # リソースファイルを格納するディレクトリ
│   │       ├── static          # 静的リソースを格納するディレクトリ(CSSやJavaScriptファイルなど)
│   │       ├── templates       # Thymeleafなどのテンプレートエンジンによるビューファイルを格納するディレクトリ
│   │       └── application.properties   # Spring Bootの設定を格納するファイル
│   └── test                    # テストのソースコードとリソースを格納するディレクトリ
└── ...                         # その他のファイルとディレクトリ(例:pom.xml, .gitignore, README.mdなど)

所需的文件(代码)

构图(示例)

project-directory                         # プロジェクトのルートディレクトリ
├── src                                   # ソースコードを格納するディレクトリ
│   ├── main                              # メインのソースコードとリソースを格納するディレクトリ
│   │   ├── java                          # Javaソースコードを格納するディレクトリ
│   │   │   └── com                       # ここからパッケージ構造が始まる
│   │   │       └── example               # 例えば 'com.example' パッケージ
│   │   │           ├── LibraryManagementSystemApplication.java # Spring Bootアプリケーションのエントリーポイント
│   │   │           ├── controller       # controller パッケージ
│   │   │           │   ├── LoginController.java   # ログインに関する処理を行うコントローラ
│   │   │           │   └── RegisterController.java # 登録に関する処理を行うコントローラ
│   │   │           ├── model            # model パッケージ
│   │   │           │   ├── User.java    # Userエンティティのモデルクラス
│   │   │           │   └── UserDto.java # Userエンティティに関するデータ転送オブジェクト (DTO)
│   │   │           ├── repository       # repository パッケージ
│   │   │           │   └── UserRepository.java  # Userエンティティに関するリポジトリインターフェース
│   │   │           └── service          # service パッケージ
│   │   │               ├── UserPrincipal.java  # ユーザーの認証情報を保持するクラス
│   │   │               └── UserService.java   # Userエンティティに関するサービスクラス
│   │   └── resources                     # リソースファイルを格納するディレクトリ
│   └── test                              # テストのソースコードとリソースを格納するディレクトリ
└── ...                                   # その他のファイルとディレクトリ(例:pom.xml, .gitignore, README.mdなど)

有时根据规范,可能将”model”目录称为”entity”目录。

图书馆管理系统应用程序.java

由于此项目名为LibraryManagementSystem,因此文件名中附有项目名。

在Spring Boot应用程序的主类中,有一个main方法作为应用程序的入口点。在main方法中调用SpringApplication.run来启动应用程序。@SpringBootApplication注解表示这个类是一个Spring Boot应用程序。

package com.example; // このファイルが属するパッケージ(フォルダ)

// 必要なクラスをインポートします
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // Spring Bootアプリケーションであることを示します
public class LibraryManagementSystemApplication { // アプリケーションのメインクラス

	public static void main(String[] args) { // Javaアプリケーションのエントリーポイント(最初に実行されるメソッド)
		SpringApplication.run(LibraryManagementSystemApplication.class, args); // Spring Bootアプリケーションを起動します
	}
}

用户.java

将用户表(User Table)与Java变量(字段)相关联

package com.example.model;  // このファイルが属するパッケージ(フォルダ)

// 以下の部分はデータベースとのやり取りに必要な情報を持つためのものです。
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity  // これはデータベースのテーブルを表しています
@Table(name = "Users")  // このクラスが対応するテーブルの名前は "Users" です
public class User {

    @Id  // これが各ユーザを一意に識別するためのIDとなります
    @GeneratedValue(strategy = GenerationType.IDENTITY)  // IDは自動的に増加します
    @Column(name = "id")  // データベースに合わせてカラム名を修正
    private Integer id;

    @Column(name = "username", nullable = false, unique = true)  // "username" カラム。各ユーザーのユーザー名を表します。同じ名前のユーザーは存在できません
    private String username;

    @Column(name = "password", nullable = false)  // "password" カラム。ユーザーのパスワードを表します
    private String password;

    @Column(name = "email", nullable = false, unique = true)  // "email" カラム。ユーザーのメールアドレスを表します。同じメールアドレスのユーザーは存在できません
    private String email;

    // 以下は各値を取得するためのメソッド(ゲッター)です。
    public Integer getId() {
        return this.id;
    }

    public String getUsername() {
        return this.username;
    }

    public String getPassword() {
        return this.password;
    }

    public String getEmail() {
        return this.email;
    }

    // 以下は各値を設定するためのメソッド(セッター)です。
    public void setId(Integer id) {
        this.id = id;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

UserDto.java的意思是Java类文件UserDto。

这是一个用来存储用户输入数据的类。用户在表单中输入的数据将被转换为此类的实例,并在应用程序中使用。@NotEmpty注释用于输入值检查,以确保目标字段不为空。这样可以防止用户发送空白数据。

package com.example.model;  // このファイルが属するパッケージ(フォルダ)

// 入力チェックをするためのツールをインポートしています。
import javax.validation.constraints.NotEmpty;

public class UserDto {  // ユーザーのデータを扱うためのクラス

    @NotEmpty  // ユーザー名は空であってはならないというルール
    private String username;  // ユーザー名を保存するための場所

    @NotEmpty  // パスワードは空であってはならないというルール
    private String password;  // パスワードを保存するための場所

    @NotEmpty  // メールアドレスは空であってはならないというルール
    private String email;  // メールアドレスを保存するための場所

    // 以下は各値を取得するためのメソッド(ゲッター)です。
    public String getUsername() {
        return username;  // ユーザー名を返す
    }

    public void setUsername(String username) {
        this.username = username;  // ユーザー名を設定する
    }

    public String getPassword() {
        return password;  // パスワードを返す
    }

    public void setPassword(String password) {
        this.password = password;  // パスワードを設定する
    }

    public String getEmail() {
        return email;  // メールアドレスを返す
    }

    public void setEmail(String email) {
        this.email = email;  // メールアドレスを設定する
    }
}


用户存储库.java

这个接口定义了一个用于对User实体进行数据库操作的仓库。通过继承JpaRepository,它可以自动提供各种数据库操作,例如保存、更新、删除和查询等。findByUsername方法是一个用于根据指定的用户名搜索用户的方法,Spring Data JPA会自动生成其实现。

package com.example.repository;  // このファイルが属するパッケージ(フォルダ)

// 必要なツールをインポートしています
import org.springframework.data.jpa.repository.JpaRepository;

// Userクラスを使うためにインポートしています
import com.example.model.User;

// UserRepositoryというインターフェースを作成します。JpaRepositoryを拡張して、UserオブジェクトとそれらのIDとしてLong型を扱えるようにします。
public interface UserRepository extends JpaRepository<User, Long> {
    // ユーザー名でユーザーを探すメソッド。ユーザー名をパラメータとして渡すと、そのユーザー名を持つユーザーをデータベースから探して返します。
	User findByUsername(String username);
}

用户主要.java

实现了Spring Security的UserDetails接口,在认证(登录)时将被Spring Security使用。它保存了用户的信息(用户名、密码、权限等),并提供这些信息。

package com.example.service; // このファイルが属するパッケージ(フォルダ)

// 必要なツールをインポートしています
import java.util.Collection;
import java.util.Collections;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

// Userクラスを使うためにインポートしています
import com.example.model.User;

// UserDetailsインターフェースを実装したUserPrincipalというクラスを作成します。これはSpring Securityでユーザー情報を扱うためのクラスです。
public class UserPrincipal implements UserDetails {

    private User user;  // Userオブジェクトを保持します。

    // コンストラクタでUserオブジェクトを受け取り、それをこのクラスのuserにセットします。
    public UserPrincipal(User user) {
        this.user = user;
    }

    // ユーザーに与えられる権限を返します。ここでは全てのユーザーに"USER"という権限を与えています。
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Collections.singleton(new SimpleGrantedAuthority("USER"));
    }

    // Userオブジェクトのパスワードを返します。
    @Override
    public String getPassword() {
        return user.getPassword();
    }

    // Userオブジェクトのユーザー名を返します。
    @Override
    public String getUsername() {
        return user.getUsername();
    }

    // アカウントが有効期限切れでないことを示すために、常にtrueを返します。
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    // アカウントがロックされていないことを示すために、常にtrueを返します。
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    // 資格情報(ここではパスワード)が有効期限切れでないことを示すために、常にtrueを返します。
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    // アカウントが有効であることを示すために、常にtrueを返します。
    @Override
    public boolean isEnabled() {
        return true;
    }
}

用户服务.java

package com.example.service; // このファイルが属するパッケージ(フォルダ)

// 必要なクラスをインポートします
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import com.example.model.User;
import com.example.model.UserDto;
import com.example.repository.UserRepository;

@Service // このクラスがサービス層のクラスであることを示します
public class UserService implements UserDetailsService { // UserDetailsServiceインターフェースを実装しています

    @Autowired // Springが自動的にUserRepositoryの実装を注入します
    private UserRepository userRepository;

    @Autowired // Springが自動的にPasswordEncoderの実装を注入します
    private PasswordEncoder passwordEncoder;

    @Override // UserDetailsServiceインターフェースのメソッドを上書きします
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username); // ユーザー名でユーザーを検索します
        if (user == null) {
            throw new UsernameNotFoundException("User not found"); // ユーザーが見つからない場合、例外をスローします
        }
        return new UserPrincipal(user); // ユーザーが見つかった場合、UserPrincipalを作成し返します
    }

    //新たにメソッドを追加します
    public User findByUsername(String username) {
        return userRepository.findByUsername(username); // ユーザー名でユーザーを検索し返します
    }

    @Transactional // トランザクションを開始します。メソッドが終了したらトランザクションがコミットされます。
    public void save(UserDto userDto) {
        // UserDtoからUserへの変換
        User user = new User();
        user.setUsername(userDto.getUsername());
        // パスワードをハッシュ化してから保存
        user.setPassword(passwordEncoder.encode(userDto.getPassword()));
        user.setEmail(userDto.getEmail());

        // データベースへの保存
        userRepository.save(user); // UserRepositoryを使ってユーザーをデータベースに保存します
    }
}


安全配置.java

这个类是用来定义Spring Security的配置。每个方法提供了与安全相关的配置。包括密码哈希化、访问控制、登录页面设置、登出设置等。

package com.example.Config; // このファイルが属するパッケージ(フォルダ)

// 必要なクラスやインターフェースをインポートします
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration // このクラスは設定クラスであることを示します
@EnableWebSecurity // Webセキュリティを有効にすることを示します
public class SecurityConfig { // セキュリティ設定のクラス

    @Bean // このメソッドの返り値をSpringのBeanとして登録します
    public PasswordEncoder passwordEncoder() { // パスワードエンコーダー(パスワードのハッシュ化)を提供するメソッド
        return new BCryptPasswordEncoder(); // パスワードをBCrypt方式でハッシュ化するエンコーダーを返します
    }

    @Bean // このメソッドの返り値をSpringのBeanとして登録します
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // セキュリティフィルタチェーンを定義するメソッド
        http
            .authorizeRequests(authorizeRequests ->  // 認証リクエストを設定します
                authorizeRequests
                    .antMatchers("/login", "/register").permitAll() // "/login"と"/register"へのリクエストは認証なしで許可します
                    .anyRequest().authenticated() // それ以外の全てのリクエストは認証が必要です
            )
            .formLogin(formLogin ->  // フォームベースのログインを設定します
                formLogin
                    .loginPage("/login") // ログインページのURLを設定します
                    .permitAll() // ログインページは認証なしで許可します
            )
            .logout(logout ->  // ログアウトを設定します
                logout
                    .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) // ログアウトのリクエストURLを設定します
            );

        return http.build(); // 上記の設定を反映してHttpSecurityオブジェクトをビルドします
    }

    // 他のセキュリティ設定が必要な場合は、ここに追加します
}


登录控制器.java

Web控制器用于处理用户的HTTP请求并返回适当的响应。@Controller注解表示这个类是一个Web控制器。@GetMapping注解指定了处理特定URL的GET请求的方法。每个方法的返回值可以是要显示的HTML页面名称或重定向的URL。

package com.example.controller; // このファイルが属するパッケージ(フォルダ)

// 必要なクラスをインポートします
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller // このクラスがWebコントローラーであることを示します
public class LoginController {

    @GetMapping("/login") // "/login"というURLに対するGETリクエストを処理します
    public String login() {
        return "login";  // login.htmlを表示します
    }
    
    @GetMapping("/") // ルートURL ("/") に対するGETリクエストを処理します
    public String redirectToIndex() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); // 現在のユーザーの認証情報を取得します
        if (authentication != null && authentication.isAuthenticated()) { // ユーザーがログインしている場合
            return "redirect:/index";  // "/index"にリダイレクトします
        }
        return "redirect:/login"; // ユーザーがログインしていない場合、"/login"にリダイレクトします
    }
    
    @GetMapping("/index") // "/index"というURLに対するGETリクエストを処理します
    public String index() {
        return "index"; // index.htmlを表示します
    }
}

注册控制器.java

这是一个处理用户注册请求的Web控制器。registerForm()方法用于显示注册表单。register(@ModelAttribute UserDto userDto)方法用于处理用户注册。如果用户名已存在,则返回注册页面。如果用户名不存在,则保存新用户并重定向到登录页面。

package com.example.controller; // このファイルが属するパッケージ(フォルダ)

// 必要なクラスをインポートします
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;

import com.example.model.User;
import com.example.model.UserDto;
import com.example.service.UserService;

@Controller // このクラスがWebコントローラーであることを示します
public class RegisterController {

    // Spring が自動的に UserService の実装を注入します
    @Autowired
    private UserService userService;

    @GetMapping("/register") // "/register"というURLに対するGETリクエストを処理します
    public ModelAndView registerForm() {
        ModelAndView mav = new ModelAndView(); // ModelAndViewオブジェクトを作成します
        mav.addObject("user", new UserDto()); // 新しいUserDtoオブジェクトを"ユーザー"という名前で追加します
        mav.setViewName("register"); // 表示するビュー(HTMLファイル)の名前を"register"に設定します
        return mav; // ModelAndViewオブジェクトを返します
    }

    @PostMapping("/register") // "/register"というURLに対するPOSTリクエストを処理します
    public String register(@ModelAttribute UserDto userDto) {
        User existing = userService.findByUsername(userDto.getUsername()); // ユーザー名で既存のユーザーを検索します
        if(existing != null){
            // ユーザーが既に存在する場合の処理
            return "register"; // ユーザーが存在するため、再度登録画面を表示します
        }
        userService.save(userDto); // ユーザーが存在しない場合、新しいユーザーを保存します
        return "login"; // 登録が成功した場合、ログイン画面を表示します
    }
}

HTML是一种用于创建网页的标记语言。

这次限定在以下的画面上。

    • ログイン画面 (login.html)

新規アカウント作成画面 (register.html)

ホーム画面 (index.html)

文件结构图

LibraryManagementSystem
├── src
   ├── main
      └── resources
          └── templates
              ├── login.html
              ├── register.html
              └── index.html
└── ...
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Login</title>
</head>
<body>
    <div th:if="${param.error}">
        <p>Invalid username and password.</p>
    </div>
    <div th:if="${param.logout}">
        <p>You have been logged out.</p>
    </div>
    <form th:action="@{/login}" method="post">
        <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
        <div>
            <label>Username: </label>
            <input type="text" name="username" required/>
        </div>
        <div>
            <label>Password: </label>
            <input type="password" name="password" required/>
        </div>
        <button type="submit">Login</button>
    </form>
    <p>
        Don't have an account? <a th:href="@{/register}">Register</a>  <!-- 新規アカウント作成ページへのリンクを追加 -->
    </p>
</body>
</html>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>テスト</h1>
</body>
</html>

【重要】关于表单数据的发送(CSRF)

在Spring Boot的Spring Security中,默认启用了CSRF(跨站请求伪造)防护。这是为了保护Web应用程序免受CSRF攻击。

具体来说,在使用表单以POST方式提交数据时,还会同时发送一个特殊的值,即CSRF令牌。服务器端会确认这个CSRF令牌是否正确,如果不正确,服务器会拒绝该请求。这样可以防止用户进行意外的操作。

另外,尽管可以禁用CSRF防护措施,但这样做会使网络应用程序易受CSRF攻击,因此通常不推荐禁用。

CSRF攻击是指跨站请求伪造的攻击方式。

恶意网站在用户登录的另一个网站上进行操作。用户可能在不知情的情况下,被篡改或删除信息。

其实是想表达什么呢?

由于CSRF(跨站请求伪造)防护措施,在指定发送数据的目标地址时,通信被服务器阻断,导致无法将数据传递到数据库,从而无法注册新账户。

<form action="/register" method="post">

在实际上使用浏览器操作时,由于可以部分地发送数据,所以不会在控制台中产生错误。
然而,由于账户没有被添加到数据库中,所以这是一个原因不太容易理解的原因之一。

关于表单数据的目标地址(CSRF防护)

如果禁用默认设置的CSRF防护功能,可以在常规的发送目标上发送请求,但不建议这样做。

只需要一种选项:
通过以下方式,您可以向数据库发送要添加的帐户,而无需对CSRF功能进行通信阻碍。

<html xmlns:th="http://www.thymeleaf.org">

th:action="@{/somepath}" のように使う
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Register</title>
</head>
<body>
    <h2>Register</h2>
    <form th:action="@{/register}" method="post">
        <label for="username">Username:</label><br>
        <input type="text" id="username" name="username" required><br>
        <label for="password">Password:</label><br>
        <input type="password" id="password" name="password" required><br>
        <label for="email">Email:</label><br>
        <input type="email" id="email" name="email" required><br>
        <input type="submit" value="Submit">
    </form>
</body>
</html>

通过这样做,账户信息将被正确地发送到数据库,并且可以添加账户。
所添加账户的密码将由SecurityConfig类进行哈希处理并注册。

 

スクリーンショット 2023-07-14 12.09.37.png
スクリーンショット 2023-07-18 10.23.04.png
スクリーンショット 2023-07-18 10.23.43.png
スクリーンショット 2023-07-18 10.24.25.png

GitHub (Chinese: GitHub)

 

后记

这次创建的文件彼此紧密相连,如果有一个文件缺失,就会在某处发生错误,只有当全部齐备时才能避免错误。此外,使用的SpringBoot、Java和Spring Security的版本也会导致错误的发生。或许这是很自然的事情,但因为无法解决Eclipse中显示的错误而感到困扰,所以我觉得有必要记住这个原因。

bannerAds