Spring Security 的作为守门员,其两大功能:认证(Authentication) 和 授权(authorization)
学而思:
- Spring Security 是如何对用户进行管理的?
初始化项目并启动
初始化一个 Spring Boot 项目并编写一个接口,在没有引入 Spring Security 依赖时,接口是能够能正常访问的。
@RestController
@RequestMapping("/user")
public class UmsAdminController {
@GetMapping("/details")
public Object userInfos() {
return "用户详情";
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
在引入依赖后,再次请求接口 http://localhost:8080/user/details
,页面跳转至了登录页面。
用户默认名为 user
, 默认密码是每次启动应用时随机生成的,启动应用时,显示在了控制台中。
UserDetailsManager
明明什么都没干,只是引入安全的框架,为什么请求接口就被拦截?
这就与 Spring Security 的机制有关,Spring Security 采用了”默认拒绝“ 的安全策略。意思是资源默认对未认证授权用户禁止访问。为需要开放的资源进行属性配置,而不是默认对资源进行开放,这被认为是一种良好的安全做法。
在请求接口前,Spring Security 采用了过滤器对接口进行拦截认证(过滤器是Security 的核心部分,这个之后再详述)。认证过程中用到 UserDetailsManager ,也就是本章的主角。
UserDetailsManager 是管理用户的接口,继承了 UserDetailsService 接口,UserDetailsService 提供了加载用户详细信息(UserDetails)的方法(loadUserByUsername) 。
- UserDetails: 用户详细信息的接口,对用户的抽象,提供了获取用户名和密码等方法
- UserDetailsService:提供了一个加载用户的方法,该方法根据用户名从存储(内存、数据库等)中查询出用户对象(UserDetails),认证过程最终就是通过调用该方法,来认证用户。
- UserDetailsManager:在 UserDetailsService 基础上增加了 增删改等功能,实现了对用户的管理。
两个实现类
在Spring Security 中 ,UserDetailsManager 有两个实现类,如下图:
- InMemoryUserDetailsManager:基于内存的用户管理器,项目初始化时默认使用,不能满足业务需求
- JdbcUserDetailsManager:基于数据库的用户管理器,更符合真实业务的需求
InMemoryUserDetailsManager
先来探索 InMemoryUserDetailsManager 在Security 中是如何构建的。
在 Spring Boot 中有一个自动配置类 UserDetailsServiceAutoConfiguration 。向Ioc 容器中注入了 InMemoryUserDetailsManager 对象。
在 构建 InMemoryUserDetailsManager 对象的同时,向其注入了一个 User对象(UserDetails 的实现类),并把一个静态类User 的 name 和 经过加工的 password1 作为 用户名和密码。
这正好对应了 前面登录时所需的用户名和密码。
但是这样的用户管理器很难满足真实业务需求,真实的用户数据存在于数据库中,因此可以重新构建 UserDetailsManager 的实现类 ,对功能进行扩展。
比如下面的 JdbcUserDetailsManager 。
JdbcUserDetailsManager
未完待续。。。
- Spring Security 提供了各种加密策略,密码前面需要添加{【加密类型】},例如:{noop}123, 表示没有加密。 ↩
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。