Spring Boot 2 整合 Spring Security

想用 Spring Boot 做一个博客,一个登录功能就把我安排得明明白白。

发现别人的登录功能是用 Spring Security 实现的,但是我并没有找到合适的教程。一会儿跟着视频写,一会儿照着别人的文章敲,折腾了半天,虽说实现了登录和退出,但总感觉自己是在闭门造车。

实现的功能

  • 首次访问提示未登录

  • 登录之后显示用户身份(用户的身份包括:USER、ADMIN)

  • 另外如果没有登录的话,是不能进入后台管理页面(/admin)的

具体实现

新建项目

  • 工具:
    • JDK1.8
    • IDEA

添加依赖

  • 第一个依赖是每个项目都需要的,就不多说了,多了我也不会。
  • 第二、三个依赖是关于 Spring Security 的,下面是这两个包的官方说明。

Web - spring-security-web.jar

Contains filters and related web-security infrastructure code. Anything with a servlet API dependency. You’ll need it if you require Spring Security web authentication services and URL-based access-control. The main package is org.springframework.security.web.

Config - spring-security-config.jar

Contains the security namespace parsing code & Java configuration code. You need it if you are using the Spring Security XML namespace for configuration or Spring Security’s Java Configuration support. The main package is org.springframework.security.config. None of the classes are intended for direct use in an application.

  • 第四个依赖我也不了解,但是如果不加这个依赖那么就不能在 HTML 根据登录状态显示指定的内容。(下面会讲如何显示指定内容的)
  • 最后一个依赖的功能是向浏览器返回一个 HTML 页面。当然了,它还有其他功能,我还没用到而已。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

修改配置

修改端口以及 thymeleaf 相关配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
server.port=80

#开发时关闭缓存,不然没法看到实时页面
spring.thymeleaf.cache=false
spring.thymeleaf.mode=HTML5
#前缀
spring.thymeleaf.prefix=classpath:/templates/
#编码
spring.thymeleaf.encoding=UTF-8
#类型
spring.thymeleaf.servlet.content-type=text/html
#名称的后缀
spring.thymeleaf.suffix=.html

新建配置类

  • 新建一个 config 文件夹,然后新建一个类。
  • 这个类继承 WebSecurityConfigurerAdapter 类,并覆盖它的两个方法,方法的作用已经写有注释了。

注意点

  • 理解一下代码的含义,比如哪些是需要登录才能访问的接口。
  • 根据下面的代码,当需要访问权限时,会自动跳转到 127.0.0.1/login 路径下,所以在 Controller 中需要添加 login 接口,使其跳转到登录页面。
  • 登录界面提交的路径同样是 127.0.0.1/login,也就是说登录表单的 action 值为 /login。
  • 登录请求提交之后,Spring Security 会自动为我们处理,如果登录成功返回上一级页面,如果失败跳转到自定义的错误页面。(这里还有个需要注意的点,后面讲 login.html 的时候会讲。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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.crypto.password.Pbkdf2PasswordEncoder;

/**
* @author diaolizhi
* @version v1.0
* @time 2018/8/12 16:49
*/
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

/**
* 配置哪些地址可以访问,哪些需要特殊的身份。
* 指定了哪个是登录接口,已经登录失败时跳转的地址
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/admin/**").hasRole("USER")
.and()
.formLogin()
// loginPage 既是需要验证时自动跳转的接口,也是接收验证信息的接口
.loginPage("/login").failureUrl("/login-error");
}

/**
* 配置用户信息
* @param auth
* @throws Exception
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
Pbkdf2PasswordEncoder encoder = new Pbkdf2PasswordEncoder();
String password = encoder.encode("admin");
auth
.inMemoryAuthentication()
.passwordEncoder(encoder)
.withUser("admin").password(password).roles("USER");
}
}

新建 Controller 类

定义 admin、login 和 login-error 接口。

由于上面的配置类,所以未登录的情况下可以访问 / 接口,但是不能访问 /admin。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

/**
* @author diaolizhi
* @version v1.0
* @time 2018/8/12 16:55
*/

@Controller
public class IndexController {

@GetMapping("/admin")
public String userIndex() {
return "/admin/index";
}

@GetMapping("/")
public String index() {
return "index";
}

@GetMapping("/login")
public String login() {
return "login";
}

@GetMapping("/login-error")
public String login_error() {
return "login-error";
}
}

新建 html 页面

先理一下思路:

  • 进来先访问首页
  • 点击登录或者访问后台管理页面将跳转到登录界面
  • 已经在配置类中添加了用户信息,所以 Spring Security 将会为我们处理登录请求
  • 登录成功,跳转回上一页
  • 失败则跳转到失败页面

所以我们需要新建四个页面。

首页

注意点

1
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
  • 上面这一句定义了一个命名空间,由此可以获取到用户的相关信息,比如是否登录。更具体的用法可以去谷歌搜索。
  • 注意下面 form 表单的 action 的写法,一定要这样写,不然就会出错。

templates 目录下的 index.html 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
>
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<b>欢迎进入首页</b>
<div th:fragment="info" sec:authorize="isAuthenticated()">
<br>
<span>您已登录,已进入后台管理页面。</span>
<a href="/admin">后台管理</a>
<table border="1px">
<tr>
<th>姓名</th>
<th>身份</th>
</tr>
<tr>
<td sec:authentication="name"></td>
<td sec:authentication="principal.authorities"></td>
</tr>
</table>
<br>
<form th:action="@{/logout}" method="post">
<input type="submit" value="退出登录">
</form>
<br>
</div>
<div sec:authorize="isAnonymous()">
<span>您尚未登录,点击下方链接登录。</span>
<br>
<a href="/login">登录</a>
</div>
</body>
</html>

后台管理页面

这个文件就没什么需要注意的了。

在 templates 目录下新建一个 admin 目录,再新建一个 index.html 文件:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>后台管理</title>
</head>
<body>
<h1>后台管理页面。</h1>
</body>
</html>

登录失败页面

这个文件也没什么需要注意的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录失败</title>
</head>
<body>
<b>登录失败,用户名或密码错误。</b>
<br>
<a href="/">返回首页</a>
<br>
<a href="/login">重新登录</a>
</body>
</html>

登录界面

这个文件有一点非常需要注意,就是 action 那里,本以为两种写法没有什么区别,但是就是因为这里导致我花了很多时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<!--下面这里不能直接 action="/login",因为那样的话,验证成功之后是不会自动跳转的。-->
<form th:action="@{/login}" method="post">
<div>
<lable>用户名:</lable>
<input type="text" name="username">
</div>
<div>
<lable>密码</lable>
<input type="password" name="password">
</div>
<input type="submit" value="登录">
</form>
</body>
</html>

很多东西只是会用一点点,却不知道它真正的用途是什么,也不知道还有那些用法,我还需要很长时间的学习。

总说网上学习资源多,但是有时候我真找不到我想要的,不知道是我找不到还是真的就没有。