![d5d11f979c8e1c2f8480d95e2d188fdf.png](https://i-blog.csdnimg.cn/blog_migrate/c953c3e3a36059c5e143f794112b8147.jpeg)
成功需要成本,时间也是一种成本,对时间的珍惜就是对成本的节约
【Spring Security:安全管理框架】
主要内容
- Spring Security 简介
- 第一个Spring Security项目
- UserDetailsService详解
- PasswordEncoder密码解析器详解
- 自定义登录逻辑
- 自定义登录逻辑(数据库访问方式)
- 自定义登录页面
- 认证过程其他常用配置
- 完整认证流程
一、 Spring Security简介
1. 概括
Spring Security是一个高度自定义的安全框架。利用Spring IoC/DI和AOP功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。
使用Spring Secruity的原因有很多,但大部分都是发现了javaEE的Servlet规范或EJB规范中的安全功能缺乏典型企业应用场景。同时认识到他们在WAR或EAR级别无法移植。因此如果你更换服务器环境,还有大量工作去重新配置你的应用程序。使用Spring Security 解决了这些问题,也为你提供许多其他有用的、可定制的安全功能。
正如你可能知道的关于安全方面的两个主要区域是“认证”和“授权”(或者访问控制)。这两点也是Spring Security重要核心功能。“认证”,是建立一个他声明的主体的过程(一个“主体”一般是指用户,设备或一些可以在你的应用程序中执行动作的其他系统),通俗点说就是系统认为用户是否能登录。“授权”指确定一个主体是否允许在你的应用程序执行一个动作的过程。通俗点讲就是系统判断用户是否有权限去做某些事情。
2. 历史
Spring Security 以“The Acegi Secutity System for Spring” 的名字始于2003年年底。其前身为acegi项目。起因是Spring开发者邮件列表中一个问题,有人提问是否考虑提供一个基于Spring的安全实现。限制于时间问题,开发出了一个简单的安全实现,但是并没有深入研究。几周后,Spring社区中其他成员同样询问了安全问题,代码提供给了这些人。2004年1月份已经有20人左右使用这个项目。随着更多人的加入,在2004年3月左右在sourceforge中建立了一个项目。在最开始并没有认证模块,所有的认证功能都是依赖容器完成的,而acegi则注重授权。但是随着更多人的使用,基于容器的认证就显现出了不足。acegi中也加入了认证功能。大约1年后acegi成为Spring子项目。
在2006年5月发布了acegi 1.0.0版本。2007年底acegi更名为Spring Security。
二、 第一个Spring Security项目
1. 导入依赖
Spring Security已经被Spring boot进行集成,使用时直接引入启动器即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. 访问页面
导入spring-boot-starter-security启动器后,Spring Security已经生效,默认拦截全部请求,如果用户没有登录,跳转到内置登录页面。
在项目中新建login.html页面后
在浏览器输入:http://localhost:8080/login.html 后会显示下面页面
![c78d01b3c4c16615c5df1168f6f8dba1.png](https://i-blog.csdnimg.cn/blog_migrate/1e3ab5be821de04c066a73407d85fc1e.png)
默认的username为user,password打印在控制台中。当然了,同学们显示的肯定和我的不一样。
![e0fb7f884f4802d3e526d6b4ee8b44fe.png](https://i-blog.csdnimg.cn/blog_migrate/cabf8104bac4882f2fe34145df14932f.png)
在浏览器中输入账号和密码后会显示login.html页面内容。
3. 应用场景
3.1 对已有项目添加认证功能
在很多技术中都可能有web访问控制页面。例如:solr就有web管理页面。不需要进行登录,只要知道ip和端口任何人都可以进行访问的。可能导致solr中数据不安全问题。为了保证数据安全性,可以想办法添加Spring Security。(实际上无法添加的,非maven项目)后面还会学很多其他技术,也可以按照这个思想进行操作。
3.2 对常规项目
需要有权限控制的项目都可以使用Spring Security。
4. 可以自定义用户名和密码
通过修改application.properties(application.yml)
spring.security.user.name=smallming
spring.security.user.password=smallming
三、 UserDetailsService详解
当什么也没有配置的时候,账号和密码是由Spring Security定义生成的。而在实际项目中账号和密码都是从数据库中查询出来的。 所以我们要通过自定义逻辑控制认证逻辑。
如果需要自定义逻辑时,只需要实现UserDetailsService接口即可。接口定义如下:
![200d07ba10198d92659010d9afc33945.png](https://i-blog.csdnimg.cn/blog_migrate/3d06cfe71140e86d8b02c653a33507a1.png)
1. 返回值
返回值UserDetails是一个接口,定义如下:
![eb56d5b9a48f067b8557a32dae3c69f9.png](https://i-blog.csdnimg.cn/blog_migrate/d1d0f574615a7379aad3459d282c3aef.jpeg)
要想返回UserDetails的实例就只能返回接口的实现类。Spring Security中提供了如下的实例。对于我们只需要使用里面的User类即可。注意User的全限定路径是:
org.springframework.security.core.userdetails.User
此处经常和系统中自己开发的User类弄混。
![b809fd38343b20c48ef813e9cf52faae.png](https://i-blog.csdnimg.cn/blog_migrate/7ebca8b9e143810897701e723136061d.png)
在User类中提供了很多方法和属性。
![d4eeb82bc9b7296e8329c95bd8e958ab.png](https://i-blog.csdnimg.cn/blog_migrate/6a88aa8c740f2ee923c73a2846a244dc.jpeg)
其中构造方法有两个,调用其中任何一个都可以实例化UserDetails实现类User类的实例。而三个参数的构造方法实际上也是调用7个参数的构造方法。
- username:用户名
- password:密码
- authorities:用户具有的权限。此处不允许为null
![7d7f8d2cbd99ce45db785e3d8158e558.png](https://i-blog.csdnimg.cn/blog_migrate/426f4aa23c7a3ad82605105045752df5.png)
此处的用户名应该是客户端传递过来的用户名。而密码应该是从数据库中查询出来的密码。Spring Security会根据User中的password和客户端传递过来的password进行比较。如果相同则表示认证通过,如果不相同表示认证失败。
authorities里面的权限对于后面学习授权是很有必要的,包含的所有内容为此用户具有的权限,如有里面没有包含某个权限,而在做某个事情时必须包含某个权限则会出现403。通常都是通过AuthorityUtils.commaSeparatedStringToAuthorityList(“”)来创建authorities集合对象的。参数时一个字符串,多个权限使用逗号分隔。
2. 方法参数
方法参数表示用户名。此值是客户端表单传递过来的数据。默认情况下必须叫username,否则无法接收。
3. 异常
UsernameNotFoundException 用户名没有发现异常。在loadUserByUsername中是需要通过自己的逻辑从数据库中取值的。如果通过用户名没有查询到对应的数据,应该抛出UsernameNotFoundException,系统就知道用户名没有查询到。
四、 PasswordEncoder密码解析器详解
Spring Security要求容器中必须有PasswordEncoder实例(客户端密码和数据库密码是否匹配是由Spring Security 去完成的,Security中还没有默认密码解析器)。所以当自定义登录逻辑时要求必须给容器注入PaswordEncoder的bean对象
1. 接口介绍
encode():把参数按照特定的解析规则进行解析。
matches()验证从存储中获取的编码密码与编码后提交的原始密码是否匹配。如果密码匹配,则返回true;如果不匹配,则返回false。第一个参数表示需要被解析的密码。第二个参数表示存储的密码。
upgradeEncoding():如果解析的密码能够再次进行解析且达到更安全的结果则返回true,否则返回false。默认返回false。
![eb3fa0e871e7e6cb51d9ed52462df06d.png](https://i-blog.csdnimg.cn/blog_migrate/7c693f83b3327309d246401f47a39a1d.png)
2. 内置解析器介绍
在Spring Security中内置了很多解析器。
![88d789621f9787eb34782b3eedf955ba.png](https://i-blog.csdnimg.cn/blog_migrate/28545a3a52f9a0e816a10626bc7bfe22.jpeg)
3. BCryptPasswordEncoder简介
BCryptPasswordEncoder是Spring Security官方推荐的密码解析器,平时多使用这个解析器。
BCryptPasswordEncoder是对bcrypt强散列方法的具体实现。是基于Hash算法实现的单向加密。可以通过strength控制加密强度,默认10.
4. 代码演示
在项目src/test/java下新建com.bjsxt.MyTest测试BCryptPasswordEncoder用法。
@SpringBootTest
@RunWith(SpringRunner.class)
public class MyTest {
@Test
public void test(){
//创建解析器
PasswordEncoder encoder = new BCryptPasswordEncoder();
//对密码进行加密
String password = encoder.encode("123");
System.out.println("------------"+password);
//判断原字符加密后和内容是否匹配
boolean result = encoder.matches("123",password);
System.out.println("============="+result);
}
}