文章目录
1. 概述
- 做项目,系统的安全性是第一位
- SpringSecurity 和 Shiro ,两者很像,除了一些类、名字不一样
- 可以做
- 认证 (你是谁)
- 授权 (你能干什么)
- 攻击防护 (防止伪造身份)
- 权限
- 功能权限
- 访问权限
- 菜单权限
- ……
2. SpringSecurity 简介
官网 : https://spring.io/projects/spring-security/
SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。
为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
其核心就是一组过滤器链,项目启动后将会自动配置。
最核心的就是 Basic Authentication Filter 用来认证用户的身份,一个在spring security中一种过滤器处理一种认证方式。
几个重要的类
webSecurityConfiguration
: 自定义 security 策略AuthenticationManagerBuilder
: 自定义认真策略@EnableWebSecurity
: 开启 WebSecurity 模式
3. 使用
1. 配置页面的访问权限
-
引入 SpringSecurity 依赖
<!--SpringSecurity --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
-
新建一个配置文件,并且继承 WebSecurityConfigurerAdapter
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { //首页可以所有人访问,但是功能页只能有权限的人能访问 http.authorizeRequests() .antMatchers("/").permitAll() // "/"根目录下的资源所有人能访问 .antMatchers("/l1/**").hasRole("vip1") // "/l1"下的所有文件只有VIP1级别的用户可以访问 .antMatchers("/l2/**").hasRole("vip2") .antMatchers("/l3/**").hasRole("vip3"); }
-
测试一下
访问 /l1 下的文件,报错 403(没有权限)
2. 登录
-
在刚刚的配置文件中添加上一句
当没有权限时,跳转到登录页//没有权限,跳转到登录页 http.formLogin();
-
再测一下
发送同样的请求,会自动跳转到登录页面
-
但是到现在都没有配置,关于自动跳转登录页的配置,所以为什么会自动跳转?
点进
formLogin
它上面有很长一段注释,看一下
“进行身份验证失败,就会发出 / login 请求,重定向到 / login?error”更多跟详细的写法:
-
定制认证的规则
还在刚刚的 SecurityConfig 配置文件中重写一个方法@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 从内存中读取认证的角色及身份 // 也可以配置从数据库读取 // 如果多个可以用 .and() 去拼接 auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) .withUser("hehe").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1") .and() .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3"); }
注意:
在 springboot 2.1.X 中可以直接使用
在更高版本中,可能会报 PasswordEncoding 的错
在 SpringSecurity 5.0+ 中增加了很多的加密方法
使用passwordEncoder(new BCryptPasswordEncoder())
进行密码编码 -
测试
登录 hehe 用户
访问 l1 目录下的页面
成功访问
访问其他等级的页面
无访问权限
3. 注销
-
在
http.formLogin();
的后面加上一句//注销 http.logout(); // 注销后跳转到指定页面 http.logout().logoutSuccessUrl("/");
-
点进
logout
"会发送 /logout 请求,然后重定向到 /login?success “
可用的配置
-
测试
4. 根据是否登录,显示不同内容
注意 :
SpringSecurity 4 和 5 整合的包名有些区别
两个版本在页面中的命名空间路径也有区别
两个版本在使用时也同样有区别
需要注意自己的版本与springboot 的版本是否匹配,不匹配不生效
-
导入 thymeleaf - SpringSecurity 整合包的依赖
<!--thymeleaf - SpringSecurity 整合包--> <!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity5 --> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity5</artifactId> </dependency>
-
在页面导入 thymeleaf - SpringSecurity 整合包的命名空间
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
-
修改首页
需求:
如果未登录,只显示登录按钮
如果已登录,显示 用户名、角色、注销按钮<!--如果未登录,则显示登录按钮--> <li sec:authorize="!isAuthenticated()"> <a th:href="@{/tologin}">登录</a> </li> <!--如果已登录,显示用户名 + 注销--> <li sec:authorize="isAuthenticated()"> <span>用户名:<span sec:authentication="name"></span></span> <span>角色:<span sec:authentication="principal.authorities"></span></span> <span><a th:href="@{/logout}">注销</a></span> </li>
-
测试
未登录
登录
5. 根据不同角色,显示不同内容
- 修改页面
- 测试
未登录
登录只有 VIP1 权限的用户
登录有所有权限的用户
6. 实现登录界面”记住我“功能
-
在 SecurityConfig 中加入
//开启记住我功能 http.rememberMe();
-
测试
已经多了这样一个单选框
登录,然后关闭浏览器
再打开浏览器,进入该页面
该用户还在 -
实现原理
把该用户信息存入浏览器的 Cookie
默认保存两周(14天)
7. 设置登录页面
- 方式一
-
进入
http.formLogin();
看源码
上面的注释中,有这样一个配置项 -
修改
http.formLogin();
http.formLogin().loginPage("/tologin");
/tologin :是去 登录页面 的请求
-
查看登录页面,提交表单的请求
-
测试
点击自己写的登录按钮,输入存在内存中的用户信息,登录成功
-
输入框的 name 属性
这里默认是必须要写成 “username” 和 “password” 不然 识别不到如果想要修改怎么办呢?
也有对应的方法
http.formLogin().usernameParameter("name").passwordParameter("pwd");
8. 配置自己的”记住我“
- 在页面上加入一个 ”记住我“
- 修改配置文件
这里rememberMeParameter
的值和页面中name
的值要一致 - 测试,浏览器被加入了 cookie,成功