认证和授权

认证(authentication)

认证意味着确认你自己的身份,是关于验证你的凭据,如用户名/邮箱和密码,以验证访问者的身份。系统确定你是否就是你所说的使用凭据。常见的认证方式有:

  • 手机和短信验证码认证
  • 用户名密码认证
  • 邮箱和邮件验证码认证

授权意味着授予对系统的访问权限。授权发生在系统完成身份认证之后,最终会授予你访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。简单来说,授权决定了你访问系统的能力以及达到的程度。

授权是确定经过身份验证的用户是否可以访问特定资源的过程。就像给予某人官方许可做某事或任何事情。

Spring Security简介

Spring Security是 Spring 家族中的一个安全管理框架,是一个功能强大且高度可定制的身份验证和访问控制框架。认证和授权就是Spring Security作为安全框架的核心功能。

官方文档地址:https://spring.io/projects/spring-security/#learn

小试牛刀

导入依赖

创建一个 Spring Boot 的 web 项目,并导入部分依赖,这里为方便测试,直接利用 Thymleaf 进行前后端交互。pom文件如下:

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
49
50
51
52
53
54
55
56
57
<?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.7.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo</groupId>
<artifactId>spsc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spsc</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--thyneleof模板-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
<!--spring security模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-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>

前端

前端展示页面较为简单,结构如下(level1/2/3分别对应vip1/2/3,login为自定义登录页,index为首页):

20201019172422525.jpg

20201019172422525.jpg

Spring Security配置

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
package com.demo.spsc.config;

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;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

//授权
//链式编程
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人都能访问,功能页只对有权限的用户开放
//请求授权的规则,角色等
http.authorizeHttpRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");

//没有权限会默认到登录页,但该页为内部默认登录页,而不是我们自己写的登录页。也可以将该方法用and()拼接到上面的链式编程上
//可以自定义登录页,前者为前往登录页,后者为登录提交url(与前端对应),参数也需对应,如不对应,也可在下面手动对应
http.formLogin().loginPage("/toLoginForm").usernameParameter("username").passwordParameter("password").loginProcessingUrl("/login");

//开启注销功能,注销后跳转到首页
http.logout().logoutSuccessUrl("/");

//开启记住我功能,利用cookie默认保存两周,参数也需和前端对应
http.rememberMe().rememberMeParameter("remember");
}

//认证,注意:在springboot2.1以上的版本中,会报错:密码未编码,在下面加入passwordEncoder方法可解决
//spring5 security5.0+的版本中,新增多种加密算法
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中进行认证,也可使用jdbc相关方法通过数据库认证
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("xlh").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
}
}

Controller

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
package com.demo.spsc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class RouterController {
@RequestMapping({"/","/index"})
public String index(){
return "index";
}

@RequestMapping("/toLoginForm")
public String toLogin(){
return "views/login";
}

@RequestMapping("/level1/{id}")
public String level1(@PathVariable("id") int id){
return "views/level1/"+id;
}

@RequestMapping("/level2/{id}")
public String level2(@PathVariable("id") int id){
return "views/level2/"+id;
}

@RequestMapping("/level3/{id}")
public String level3(@PathVariable("id") int id){
return "views/level3/"+id;
}
}

效果

20201019172422525.jpg

20201019172422525.jpg

20201019172422525.jpg