尝试使用Spring Boot实现身份验证功能

首先

我们将使用Spring Boot来构建Web应用程序环境。
这次我们将尝试创建一个需要身份验证的页面。
认证信息(用户名和密码)我们将在MySQL中进行实践性地管理。

继上一次之后,在Eclipse Neon上进行实现。

环境

    • Windows 10

 

    • Eclipse Neon

 

    • Java 1.8.0_111

 

    MySQL 5.7

指定所需的模块。

可以使用Spring Security模块实现认证处理。
使用Spring Data JPA模块进行数据库连接。
由于使用了模板引擎(Thymeleaf)进行页面创建,所以需要加载这些模块。

在Eclipse中,您可以指定在创建新项目时加载的模块,但并不总是能从新项目开始。所以,这次我们直接将定义写入build.gradle文件。在build.gradle中有一个名为dependencies的部分,您可以这样进行设置。

dependencies {
  compile('org.springframework.boot:spring-boot-starter-security')
  compile('org.springframework.boot:spring-boot-starter-data-jpa')
  compile('org.springframework.boot:spring-boot-starter-thymeleaf')
  compile('org.springframework.boot:spring-boot-starter-web')
  compile('org.springframework.boot:spring-boot-devtools')
  compile('mysql:mysql-connector-java')
  compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.5'
  testCompile('org.springframework.boot:spring-boot-starter-test')
}

数据库连接的设置

接下来是数据库连接的设置。
请将其配置在 application.properties 文件中。如有需要,请同时写入端口号。

spring.datasource.url=jdbc:mysql://[MySQL のサーバ名]/[データベース名]
spring.datasource.username=[ユーザ名]
spring.datasource.password=[パスワード]
spring.datasource.driverClassName=com.mysql.jdbc.Driver

实施

下面是翻译的方式:
准备工作做好了,接下来就是开始实施了。
我们将实施一个机制,即在表单验证成功后显示首页。
如果未进行验证,将显示登录页面。

访问成员信息

在实现访问数据库中的成员信息的处理之前,需要先创建一个用于管理成员信息的数据库表。

create table member(
    id BIGINT auto_increment,
    username VARCHAR(20) NOT NULL,
    password VARCHAR(20) NOT NULL,
    unique index (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO member (username, password)
    VALUES ('user', 'pass')
;

由于这个源码只是一个样本,所以我们会以明文形式保存密码,但如果是真实数据的话,这样的实现方式是不可取的。

准备实体类

准备与已创建的表对应的实体类。因为它用于身份验证信息,所以我们将继承UserDetails类。这个类带有各种方法。根据方法名可以看出,它们返回的是锁定状态等信息,但是这次我们将统一返回true。

package com.example.entity;

import java.util.Collection;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

@Entity
@Table(name = "member")
public class MemberEntity implements UserDetails
{
    private static final long serialVersionUID = 1667698003975566301L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable = false, unique = true)
    private String username;

    @Column(nullable = false)
    private String password;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities()
    {
        return null;
    }

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

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

    @Override
    public boolean isAccountNonExpired()
    {
        return true;
    }

    @Override
    public boolean isAccountNonLocked()
    {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired()
    {
        return true;
    }

    @Override
    public boolean isEnabled()
    {
        return true;
    }
}

创建存储库接口和服务

创建一个用于获取成员信息的类(接口)。

package com.example.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.entity.MemberEntity;

public interface MemberRepository extends JpaRepository<MemberEntity, Long>
{
    public MemberEntity findByUsername(String username);
}

此外,我们将创建一个调用存储库的服务类。

package com.example.service.impl;

import org.apache.commons.lang3.StringUtils;
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.entity.MemberEntity;
import com.example.repository.MemberRepository;

@Service
public class MemberServiceImpl implements UserDetailsService
{
    private MemberRepository memberRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
    {
        if (StringUtils.isEmpty(username))
        {
            throw new UsernameNotFoundException("");
        }

        MemberEntity memberEntity = memberRepository.findByUsername(username);
        if (memberEntity == null)
        {
            throw new UsernameNotFoundException("");
        }

        return memberEntity;
    }

    @Autowired
    public void setMemberRepository(MemberRepository memberRepository)
    {
        this.memberRepository = memberRepository;
    }
}

创建首页页面 (Chuangjian shouye ye mian)

我們將創建一個需要身份認證的頁面。

package com.example.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class TopController
{
    public static final String PAGE = "/";
    private static final String HTML = "top";

    @RequestMapping(value = TopController.PAGE, method = RequestMethod.GET)
    public String top(Model model)
    {
        return TopController.HTML;
    }
}

我也会创建模板文件,并将其放置在templates目录下。

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
</head>
<body>
  こんにちは!
  <form action="#" th:action="@{/logout}" method="POST">
    <input type="submit" value="ログアウト" />
  </form>
</body>
</html>

设置访问权限

创建一个配置类,对访问权限进行设置。
将配置信息写入源代码是现代的做法!

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder)
            throws Exception
    {
        authenticationManagerBuilder.userDetailsService(this.userDetailsService);
    }

    @Autowired
    public void setUserDetailsService(UserDetailsService userDetailsService)
    {
        this.userDetailsService = userDetailsService;
    }
}

确认动作

运行>运行为>以Spring Boot App方式启动。
启动后,请在浏览器中访问以下URL。

请问一切顺利吗?已经动起来了吗?

可以进行各种自定义。

登录页面

到目前为止,我们使用了标准的登录页面,但当然可以自己创建。
准备登录页面的控制器和模板…

package com.example.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController
{
    public static final String PAGE = "/login";
    private static final String HTML = "login";

    @RequestMapping(value = LoginController.PAGE)
    public String top(Model model)
    {
        return LoginController.HTML;
    }
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>ログイン</title>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
</head>
<body>
  <form action="" th:action="@{/login}" method="post">
    <p>
      ユーザーID:
      <input type="text" name="user" />
    </p>
    <p>
      パスワード:
      <input type="password" name="pass" />
    </p>
    <p>
      <input type="submit" value="ログイン" />
    </p>
  </form>
  <div th:if="${session['SPRING_SECURITY_LAST_EXCEPTION']} != null">
    <span th:text="${session['SPRING_SECURITY_LAST_EXCEPTION'].message}"></span>
  </div>
</body>
</html>

请添加设置。
在定义中有一个参数的位置来写用户名和密码,请确保与HTML一致。

package com.example.config;

import org.springframework.beans.factory.annotation.Autowired;
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.core.userdetails.UserDetailsService;

import com.example.web.LoginController;

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception
    {
        httpSecurity.authorizeRequests().anyRequest().authenticated();
        httpSecurity.formLogin().loginPage(LoginController.PAGE).usernameParameter("user")
                .passwordParameter("pass").permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder)
            throws Exception
    {
        authenticationManagerBuilder.userDetailsService(this.userDetailsService);
    }

    @Autowired
    public void setUserDetailsService(UserDetailsService userDetailsService)
    {
        this.userDetailsService = userDetailsService;
    }
}

稍微解释一下

春季安全

Spring Security 是一个用于实施安全措施的模块。本次我们实现了认证功能,但它还具有许多其他功能,例如CSRF防护等。认证功能还支持BASIC认证,并且可以进行自定义,例如指定认证排除的路径。

春季数据 JPA

Spring Data JPA 是一个模块,它可以在不编写 SQL 的情况下访问数据库。基本操作(在这种情况下是获取与用户名对应的记录)只需定义一个方法即可完成。非常方便!
由于这是一个深奥的领域,我建议您详细搜索一下……但是请注意,搜索结果可能包括台球协会、滑翔伞协会、举重协会等信息,所以请小心。

请参考

    • GETTING STARTED Securing a Web Application

 

    • Spring SecurityでWebの認証と認可を制御する

 

    Spring BootとSpring Securityでユーザ認証(インメモリ&独自のユーザテーブル)
广告
将在 10 秒后关闭
bannerAds