一、概述
1. 简介
- Spring Security is a framework that provides authentication, authorization, and protection against common attacks. With first class support for securing both imperative and reactive applications, it is the de-facto standard for securing Spring-based applications.
- 功能:
- 身份认证(authentication):验证
谁正在访问系统资源
,判断用户是否为合法用户。认证用户的常见方式是要求用户输入用户名和密码 - 授权(authorization):用户进行身份认证后,系统会控制
谁能访问哪些资源
,这个过程叫做授权。用户无法访问没有权限的资源 - 防御常见攻击:CSRF 等
- 身份认证(authentication):验证
- 官方文档:https://docs.spring.io/spring-security/reference/index.html
2. HelloWorld
1 | <parent> |
IndexController
1 |
|
resources/templates/index.html
1 | <html xmlns:th="https://www.thymeleaf.org"> |
- 此时访问 http://localhost:8080/test 会跳转到 SpringSecurity 提供的登录页,默认用户名是 user,密码在程序控制台
3. 在配置文件中指定用户
1 |
|
4. SpringSecurity 默认开启的功能
- 访问应用程序的任何资源都需要进行身份验证,返回 401 未经授权,并重定向到登录页面
- 提供一个默认用户 user,并生成一个随机密码记录在控制台上
- 生成默认的登录表单和注销页面,提供基于表单的登录和注销流程
- 处理跨站请求伪造(CORS)攻击和会话劫持攻击(CSRF)
- 写入 Strict-Transport-Security 以确保 HTTPS;写入 X-Content-Type-Options 以处理嗅探攻击;写入 Cache Control 来保护经过身份验证的资源;写入 X-Frame-Option s以处理点击劫持攻击
- CORS:它是浏览器的保护机制,只允许网页请求统一域名下的服务(协议、域名、端口号都一致)
- CSRF:请求参数中有一个隐藏的 _csrf 字段
二、SpringSecurity 底层原理
- SpringSecurity 的底层是传统的 Servlet 过滤器
- 架构文档:https://docs.spring.io/spring-security/reference/servlet/architecture.html
- Spring 提供了一个名为
DelegatingFilterProxy
的 Filter 实现 FilterChainProxy
是 SpringSecurity 提供的一个特殊的 Filter。FilterChainProxy 使用SecurityFilterChain
来确定应该为当前请求调用哪些 Filter 实例- 这些注册到 SpringSecurity 的 Filter 实例可用于多种不同的目的,例如身份验证、授权、漏洞保护等。过滤器会按照特定的顺序执行,以保证它们在正确的时间被调用
- 如:程序启动时,
DefaultSecurityFilterChain
加载了 16 个 Filter
三、自定义认证配置
1. 基于内存的用户认证
WebSecurityConfig
1 |
|
2. 基于数据库的用户认证
pom.xml
1 | <!-- mysql --> |
application.yml
1 | spring: |
SysUser
1 |
|
UserDetailsServiceImpl
1 |
|
WebSecurityConfig
1 |
|
SysUserController
1 |
|
3. 自定义登陆界面
LoginController
1 |
|
resources/templates/login.html
1 |
|
WebSecurityConfig
1 |
|
4. 获取用户数据
SysUserController
1 |
|
四、授权
1. 基于配置的授权
1 | http.authorizeRequests(authorize -> { |
2. 基于方法的授权
WebSecurityConfig
1 | // 开启方法授权 |
SysUserController
1 |
|
五、前后端分离
1. 登录成功后
1 | public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler { |
2. 登录失败后
1 | public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { |
3. 登出成功后
1 | public class MyLogoutSuccessHandler implements LogoutSuccessHandler { |
4. 请求未认证时
1 | public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint { |
5. 无权访问时
1 | public class MyAccessDeniedHandler implements AccessDeniedHandler { |
6. Session 过期后
1 | public class MySessionInformationExpiredStrategy implements SessionInformationExpiredStrategy { |
7. 整体配置
1 |
|
六、认证流程源码解析
UsernamePasswordAuthenticationFilter
1 | public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { |
ProviderManager
1 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { |
AbstractUserDetailsAuthenticationProvider
1 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { |
DaoAuthenticationProvider
1 | protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { |