上一篇:Spring Security OAuth2.0 认证协议【6】准备 RESTful API:swagger、WireMock
下一篇:https://blog.csdn.net/LawssssCat/article/details/105296640
至此,前面的环境搭建,接口准备结束,进入 Spring Security 正题。
代码下载:https://github.com/LawssssCat/v-security/tree/v2.0
内容简介
- Spring Security 基本原理
- 用户名 + 密码认证
- 手机号 + 短信认证
会以表单登录为起点,逐渐添加概念和扩展场景,最终形成较为复杂的案例。
HTTP Basic 认证
spring security 默认就是 http basic 认证,我们只需要:
重新打开 spring security,并运行程序
只要添加了 spring security 就会默认开启 httpbasic 模式,之前开发 api 关了,现在打开,并运行。
测试
访问: http://localhost:8080/user/1
就到了我们熟悉的 httpBasic 认证了
如果看不到 http basic 认证,
而是 page not found
只需要去到全局处理,把 自定义的 ErrorController 实现类去掉即可
(当时是处理 404 请求,而开启 security 后,404 会到认证界面,且security优先级更低,因此会到 上面界面,而不是security 的 http basic 认证。如果两个都想开,那么调下优先级即可)
表单认证
<mark>提高代码重用性,所以所有跟认证授权相关的代码会写在 v-security-browser 里面,而 v-security-demo 只是使用 browser 的写好安全模块</mark>。
编写安全配置类
<mark>在 v-security-borwser 模块中</mark>
创建 package:cn.vshop.security.browser
创建类 BrowserSecurityConfig
package cn.vshop.security.browser;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/** * {@link WebSecurityConfigurerAdapter}: * spring security 提供的 {@link WebSecurity} 适配器 * 一个帮我们实现了大部分{@link WebSecurityConfigurer}接口的抽象类 * <p> * 提供了可以重写的configure方法,在方法内可以装配自定义的Filter配置 * 其指定的Filter会被生产为{@link FilterChainProxy} * 最终以{@link DelegatingFilterProxy}作为spring Security Filter Chain起作用 * <p> * 即:其实现是用来配置spring Security Filter Chain的 * * * @author alan smith * @version 1.0 * @date 2020/4/3 12:15 */
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// 指定身份认证方式为表单
http.formLogin()
.and()
// 并且认证请求
.authorizeRequests()
// 全部请求,都需要认证
.anyRequest().authenticated();
}
}
启动并访问
Spring Security 基本原理
Spring Security 其实就是一堆的过滤器链(如下图绿色部分)
其中
UsernamePasswordAuthenticationFilter
对应的是表单 登录BasicAuthenticationFilter
对应的则是 HttpBasic 登录
<mark>身份认证</mark> 流程
- 判断是否登录请求
- 查看是否携带登录名、密码
- 如果有用户名密码,就尝试使用
UsernamePasswordAuthenticationFilter
登录
- 如果有用户名密码,就尝试使用
- 如果没有,就把请求交给下一个过滤器
- 如果请求头中有 basic 开头的 authentication 的信息,就会交给
BasicAuthenticationFilter
处理
- 如果请求头中有 basic 开头的 authentication 的信息,就会交给
<mark>请求拦截</mark> 流程
在交给 (上图绿色)认证过滤器处理后,最终会来到 FilterSecurityInterceptor
*** (如下图橙色)
(过滤器、***知识在 第四章 末尾有讲)
FilterSecurityInterceptor
可以理解为最终的守门人,在他身后的,便是我们编写的 REST API 服务了。
能否真正访问到 这些服务,全由 FilterSecurityInterceptor
决定。
<mark>而决定的依据就是我们上面写的代码</mark>
<mark>错误处理</mark> 流程
如果 FilterSecurityInterceptor
判断了不能访问,会根据不同访问的原因抛出响应的异常。
这些异常的处理***是位于 FilterSecurityInterceptor
前面的 ExceptionTranslationFilter
(如下图蓝色)
ExceptionTranslationFilter
处理的依据 1、是根据抛出的异常。2、是根据我们写的认证形式
<mark>而我们要做的 spring Security 开发,就是添加 绿色的过滤器</mark>
源码分析
眼见为实
<mark>有了上面原理,下面我们打断点,跟着源码走一遍</mark>
## 打断点
第一个断点
打在 UserController 的 query 方法上,<mark>代表最终认证成功</mark>
第二断点
FilterSecurityInterceptor
(示意图中的橙色) 的 invok 方法上打断点
(打在 token 上,代表认证结束)
第三个断点
ExceptionTranslationFilter
上打断点,看出现认证异常后的处理
第四个断点
打在 UsernamePasswordAuthenticationFilter 上,看看如何密码认证的
(我们后面要自定义,即覆盖这里的操作的)
## Debug
程序 debug 运行起来 ,依次访问,观测运行流程
-
访问: http://localhost:8080/user
因为没有携带登录信息,所以直接通过(原理图中)绿色的过滤器,来到了(原理图中)蓝色的异常过滤器,并且准备往下面的***传递
来到 FilterSecurityInterceptor 进行判断能否访问后面的请求
(因为没有登录,所以,拿到token 这一步会报错,异常会返回到 上面的 ExceptionTranslationFilter)
捕获到了异常,然后就是重定向到登录页面
直接放行,前端就会显示登录页面
-
输入用户名密码登录
会来到 UsernamePasswordAuthenticationFilter 的 attemptAuthentication 方法
继续往下,就进到我们写的 api 里面了