Spring 全家桶之 Spring Security(二)
## 什么是认证?什么事授权?
### 认证(Authentication):
  认证的主要作用是识别当前用户是否是系统中的有效用户
### 授权(Authorization):
  授权的主要作用是给登录系统的用户的角色授予该角色角色所能访问的菜单列表或者能操作的功能
## RBAC 是什么
### RBAC 概念
  RBAC 既 Role Base Access Control 给予角色的访问控制,在 RBAC 的概念中,权限与角色相关联,用户拥有特定的角色从而可以自动获取这些角色的权限,这样会简化权限的管理,基本思想就是对系统的各种操作权限不应该直接赋给用户,而是在用户集合和权限集合之间建立一个角色集合,每一种角色都对应一组响应的权限,一旦用户被分配了适当的角色后,该用户就拥有了角色的所有操作权限,创建用户时只需要给用户分配角色,就可以获取一组权限,设计好角色对应的权限集合,就能很好的简化权限的管理。RBAC 中用户是属于角色的,角色拥有权限的集合,用户属于某个角色,该用户就拥有角色对应的权限,如后台管理系统中普通用户只能查看数据,管理员可以修改数据。
### RBAC 表设计
  基于 RBAC 的数据库表设计,至少含有四个表,用户表包含用户名密码是否启用等字段,角色表包含角色名称角色表述等字段,角色和用户是多对多的关系,需要一个中间表来关联用户和角色的关系,角色和用户关系表包含用户 ID 和角色 ID 两个字段,还有一个权限表,表示角色由哪些权限,权限可以由 uri 来表示
## Spring Security 中的认证接口和类
1)UserDetails: interface,用户信息接口
Methods:
boolean isAccountNonExpired(); 账号是否过期
boolean isAccountNonLocked();账号是否锁定
boolean isCredentialsNonExpired();证书是否过期
boolean isEnabled();账号是否启用
Collection<? extends GrantedAuthority> getAuthorities(); 权限集合
Implements Class:
User
![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fb1cfa86d3f4443894cad508af3cb28f~tplv-k3u1fbpfcp-watermark.image?)
常用方法:User.builds(),User.withUsername().password().roles()
可以自定义类实现 UserDetails 接口,作为系统中的用户类。
2)UserDetailsService:interface,用户信息 Service 接口
获取用户信息,得到 UserDetails 对象,需要自定义类实现接口,从数据库中获取数据,
需要实现方法 UserDetails loadUserByUsername(String var1) :根据用户名称,获取用 户信息(用户名称,密码,角色结合,是否可用,是否锁定等信息)
UserDetailsService 接口的实现类有
I:InMemoryUserDetailsManager:在内存中维护用户信息。使用方便,但是数据只保存在内存中,重启后数据丢失
II: JdbcUserDetailsManager: 用户信息存储在数据库中,使用 Spring 的 JDBC Template 操作数据,可以完成创建,更新,删除,判断是否存在等功能
![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7a44c20a5d224ac195f27efaeb37a401~tplv-k3u1fbpfcp-watermark.image?)
### InMemoryUserDetailsManager 类的使用
1.新建一个 maven 项目并加入依赖
```xml
<!--加入 spring boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<!--指定依赖-->
<dependencies>
<!--web 开发相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
```
2.在 config 包中创建应用的配置类
1)创建密码的处理类对象
2)使用 InMemoryUserDetailsManager 创建用户
``` java
@Configuration
public class ApplicationSecurityConfig {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService(){
PasswordEncoder passwordEncoder = passwordEncoder();
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
// 创建内存中用户,赋予 ADMIN 角色和 USER 角色
manager.createUser(User.withUsername("admin")
.password(passwordEncoder.encode("12345"))
.roles("ADMIN","USER").build());
manager.createUser(User.withUsername("thor")
.password(passwordEncoder.encode("12345"))
.roles("USER").build());
return manager;
}
}
```
3.在 config 包中创建 WebSecurityCinfigurerAdapter
```java
@EnableWebSecurity
public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.userDetailsService(userDetailsService);
}
}
```
4.在 controller 包中创建 Controller 控制器
``` java
@RestController
public class HelloSecurityController {
@GetMapping("/hello")
public String helloUserAndAdmin(){
return "Hello Spring Security";
}
}
```
5.创建 SpringBoot 应用启动类
``` java
@SpringBootApplication
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class,args);
}
}
```
启动应用,浏览器地址输入 http://localhost:8080 会自动跳转至 http://localhost:8080/login
![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b57185b3564741c8bda1ea4b3b0a974b~tplv-k3u1fbpfcp-watermark.image?)
### JdbcUserDetailsManager 类使用
1.首先创建数据表,拷贝 users.ddl 文件,作简要修改
```sql
create table users(username varchar(50) not null primary key,password varchar(500) not null,enabled boolean not null);
create table authorities (username varchar(50) not null,authority varchar(50) not null,constraint fk_authorities_users foreign key(username) references users(username));
create unique index ix_auth_username on authorities (username,authority);
```
2.创建一个新的 maven 项目并添加依赖
```xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
```
3.在 application.properties 中配置数据源
```properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
```
4.在 config 包中创建配置类
```java
@Configuration
public class SecurityConfig {
@Autowired
private DataSource dataSource;
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean // bean id 为 jdbcUserDetailsManager
public UserDetailsService jdbcUserDetailsManager(){
PasswordEncoder passwordEncoder = passwordEncoder();
JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource);
manager.createUser(User.withUsername("odin")
.password(passwordEncoder.encode("12345"))
.roles("ADMIN","MANAGER","USER")
.build());
manager.createUser(User.withUsername("thor")
.password(passwordEncoder.encode("12345"))
.roles("MANAGER","USER")
.build());
manager.createUser(User.withUsername("loki")
.password(passwordEncoder.encode("12345"))
.roles("USER")
.build());
return manager;
}
}
```
``` java
@EnableWebSecurity
public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Resource //根据 bean id 导入
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
super.congfigure(http);
http.userDetailsService(userDetailsService);
}
}
```
5.创建 SpringBoot 应用启动类
``` java
@SpringBootApplication
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class,args);
}
}
```
启动应用,浏览器地址输入 http://localhost:8080 会自动跳转至 http://localhost:8080/login 可以实现认证功能
![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b57185b3564741c8bda1ea4b3b0a974b~tplv-k3u1fbpfcp-watermark.image?)
评论