使用Spring-Boot和Spring-Security进行数据库认证
首先
我是最近开始学习Spring Boot的编程初学者。
我试图使用Spring Security实现DB认证,但遇到了比想象中更多的困难,所以我写了一篇文章作为备忘录。
由于我只实现了真正必要的最基本功能,所以我认为这篇文章适用于那些想使用Spring Security进行DB认证的人们。
环境 – Huan Jing
-
- Eclipse 4.19.0
-
- SpringBoot 2.5.3
-
- Java11
-
- ビルドツール:Maven
-
- テンプレートエンジン:Thymeleaf
-
- O/Rマッパー:MyBatis
- DB:MySQL

导出完成的pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>Login6</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Login6</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
项目文件夹的结构

UserModel.java
DBから取得したユーザ―情報を格納するEntityクラス
UserDetailsをimplementsする
UserListMapper.java
Mapperインターフェース (MyBatisで使用するため詳細説明は省略)
UserListMapper.xml
Mapperインターフェースに対応するXMLファイル(MyBatisで使用するため詳細説明は省略)
UserService.java
サービスクラス
UserDetailsServiceをimplementsして実装する
MainController.java
コントローラークラス
Login6Application.java
SpringBootの起動クラス
WebSecurityConfig.java
SpringSecurityの設定を行うクラス
WebSecurityConfigurerAdapterをextendsして実装する
loginForm.html
ログイン認証を行う画面
success.html
ログイン認証に成功した時に遷移する画面
application.properties
DBへの接続情報を記述しているファイル
mybatis-config.xml
MyBatisの設定ファイル
pom.xml
プロジェクトのビルドに関する情報やライブラリの依存関係などが記述されているファイル
登录6应用程序.java
这是SpringBoot的启动类。除了添加了MyBatis的配置之外,其他都是默认的。
package com.example;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
@SpringBootApplication
@MapperScan(basePackages="com.example.persistence")
public class Login6Application {
public static void main(String[] args) {
SpringApplication.run(Login6Application.class, args);
}
// MyBatisの設定
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
// コンフィグファイルの読み込み
sessionFactory.setConfigLocation(new ClassPathResource("/mybatis-config.xml"));
return sessionFactory.getObject();
}
}
主控制器.java
这是一个控制器类。
package com.example.web;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MainController {
@RequestMapping("/loginForm")
public String loginForm() {
return "loginForm";
}
@RequestMapping(value = "/loginForm", params = "error")
public String error(Model model) {
model.addAttribute("errorMsg", "ログイン認証に失敗しました");
return "loginForm";
}
@RequestMapping("/success")
public String success() {
return "success";
}
}
WebSecurity配置文件
这是一个用于SpringSecurity配置的类。虽然具体详细信息已在代码的注释中进行了说明,但是在这个类中进行了登录认证的具体配置。
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.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;
import com.example.service.UserService;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Override
protected void configure(HttpSecurity http) throws Exception {
//アクセスポリシーの設定
http.authorizeRequests()
//指定したパターンごとに制限をかける
.antMatchers("/js/**", "/css/**").permitAll()//制限なし
.anyRequest().authenticated();//上記以外は制限あり
//フォーム認証の設定
http.formLogin()
/*ログインページの指定(指定なしの場合デフォルトのものが用意される)
コントローラークラスでこのURLをマッピングしておく*/
.loginPage("/loginForm")
/*ログイン処理のパス(このURLへリクエストが送られると認証処理が実行される)
ログインページのformタグのth:action属性にこのURLを指定しておく*/
.loginProcessingUrl("/login")
/*ログインページのログイン情報入力欄のname属性に以下の名称を指定する*/
.usernameParameter("user")
.passwordParameter("pass")
/*ログイン成功時に遷移するページ(trueで成功時は常にここに飛ぶ)
コントローラークラスでこのURLをマッピングしておく*/
.defaultSuccessUrl("/success", true)
/*失敗時の遷移先、アクセス制限は解除する
コントローラークラスでこのURLをマッピングしておく*/
.failureUrl("/loginForm?error").permitAll();
}
/**
* 認証するユーザー情報をデータベースからロードする処理
* @param auth 認証マネージャー生成ツール
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
///認証するユーザー情報をデータベースからロードする
//その際、パスワードはBCryptでハッシュ化した値を利用する
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
/**
* パスワードをBCryptでハッシュ化するクラス
* ハッシュ化するクラスも幾つか種類があるみたいです
* @return パスワードをBCryptで暗号化するクラスオブジェクト
*/
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
用户服务.java
这是一个实现了UserDetailsService的服务类。唯一需要实现的方法是loadUserByUsername,它接受一个用户名(这里是id)作为参数并返回用户信息。在这里,我们使用了MyBatis作为O/R映射器,并调用了mapper接口的certificate方法。
package com.example.service;
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.stereotype.Service;
import com.example.persistence.UserListMapper;
@Service
public class UserService implements UserDetailsService{
@Autowired
private UserListMapper userListMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userListMapper.certificate(username);
}
}
用户模型.java
这是一个用来存储从数据库获取的用户信息的实体类。
通过实现UserDetails接口,实现了UserDetails中描述的方法。
package com.example.domain;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class UserModel implements UserDetails{
private String id;
private String pass;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
//1つのユーザーがROLEを複数持つときに使うみたい
return null;
}
@Override
public String getPassword() {
//パスワードを返す
return pass;
}
@Override
public String getUsername() {
//ユーザー名(今回はid)を返す。
return id;
}
@Override
public boolean isAccountNonExpired() {
//ユーザアカウントが認証期限切れしていないかどうかを返す
//認証期限切れしている場合falseを返すが、今回は特に考慮していないので
//固定でtrueを返しておく(以下メソッドでも同様の理由でtrueを返している)
return true;
}
@Override
public boolean isAccountNonLocked() {
//ユーザアカウントがロックしていないかどうか
return true;
}
@Override
public boolean isCredentialsNonExpired() {
//ユーザアカウントの資格が認証期限切れしていないかどうか
return true;
}
@Override
public boolean isEnabled() {
//ユーザアカウントが無効になっていないか
return true;
}
}
用户列表映射器.java
这是一个映射器接口类。
涉及到MyBatis的内容,因此省略了解释。
package com.example.persistence;
import org.apache.ibatis.annotations.Param;
import com.example.domain.UserModel;
public interface UserListMapper {
public UserModel certificate(@Param("id") String id);
}
使用者列表映射器.xml
这是与Mapper接口类对应的xml文件。类似地,不再赘述。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC
"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.persistence.UserListMapper">
<select id="certificate" resultType="com.example.domain.UserModel">
SELECT id, pass FROM userlist WHERE id = #{id}
</select>
</mapper>
登录表单.html
这是一个用于进行登录认证的界面。
需要在WebSecurityConfig.java中设置UserID和Password输入栏的name属性以及form标签的th:action属性,然后进行描述。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ログイン認証</title>
</head>
<body>
<form th:action="@{/login}" method="post">
<span th:if="${errorMsg}" th:text="${errorMsg}"></span><br>
UserID:<input type="text" name="user" /><br>
Password:<input type="password" name="pass" /><br>
<input type="submit" value="認証"/>
</form>
</body>
</html>
成功的.html
这是在登录验证成功时跳转到的页面。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>認証成功</title>
</head>
<body>
認証成功!!!
</body>
</html>
应用程序属性。
在这里记录了与数据库的连接信息。
#DBのドライバ設定
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#接続用URL
spring.datasource.url=jdbc:mysql://XXX/XXX
#ユーザ名
spring.datasource.username=XXX
#パスワード
spring.datasource.password=XXX
mybatis-config.xml的翻译将取决于上下文,以下提供几种可能的翻译选项:
1. MyBatis配置文件(mybatis-config.xml)
2. MyBatis配置(mybatis-config.xml)
3. MyBatis的配置文件(mybatis-config.xml)
4. MyBatis的配置(mybatis-config.xml)
5. MyBatis的XML配置文件(mybatis-config.xml)
请根据具体情况选择适合的翻译。
我正在描述MyBatis的配置信息。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC
"-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
</configuration>
表格定义
我将为您提供表格信息作为参考。
顺便一提,输入的密码将被哈希化,并与预先在数据库中注册的密码(其哈希值)进行比较。
因此,要存储在数据库中的密码需要提前进行哈希化。
在这种情况下,我们建议使用BCryptPasswordEncoder类对密码进行预先哈希化,并将其注册到数据库中。
CREATE TABLE userlist (
id int NOT NULL,
pass varchar(60) DEFAULT NULL,
PRIMARY KEY (`id`)
)
参考文章
《SpringSecurity参考文献》
尝试使用Spring Boot Security + DB身份验证的要点
最初的Spring Security-表单验证和页面跳转
Spring Security用法备忘录:身份验证和授权
尝试在Spring Boot中实现登录功能