SpringBoot Security
关于 SpringBoot Security
安全框架,以及在项目中如何使用(未完成)
Spring Security
什么是 Spring Security
一个安全框架
主要负责实现两大功能:认证与授权
事实上就是一系列具有特定功能的过滤器组合成为的一个过滤链(Filler Chain)
过滤器链解析
**ChannelProcessingFilter
**:确保请求通过正确的通道(HTTP 或 HTTPS)传输。
**WebAsyncManagerIntegrationFilter
**:集成 Spring Security 与 Spring Web 的异步请求处理。
**SecurityContextPersistenceFilter
**:负责从 HttpSession
中加载 SecurityContext
,并在请求处理完成后将其存储回 HttpSession
。
**HeaderWriterFilter
**:用于添加安全相关的 HTTP 头,例如 X-Content-Type-Options
、X-Frame-Options
、X-XSS-Protection
等。
**CsrfFilter
**:防止跨站请求伪造(CSRF)攻击。
**LogoutFilter
**:处理用户注销请求。
UsernamePasswordAuthenticationFilter
负责处理我们在登录界面填写了用户名和密码后的登陆请求。负责认证工作
处理基于用户名和密码的身份验证请求。
**DefaultLoginPageGeneratingFilter
**:生成默认的登录页面(如果未提供自定义登录页面)。
**DefaultLogoutPageGeneratingFilter
**:生成默认的注销页面(如果未提供自定义注销页面)。
**BasicAuthenticationFilter
**:处理 HTTP Basic 认证请求。
**RequestCacheAwareFilter
**:确保用户在登录后重定向到他们最初请求的 URL。
**SecurityContextHolderAwareRequestFilter
**:将 SecurityContext
中的信息添加到 HttpServletRequest
中。
**AnonymousAuthenticationFilter
**:为未认证的用户提供匿名身份。
**SessionManagementFilter
**:管理用户会话,包括并发会话控制和会话固定攻击防护。
ExceptionTranslationFilter
处理认证和授权过程中抛出的异常,并将用户重定向到适当的错误页面。
处理 AccessDeniedException
AuthenticationException
FilterSecurityInterceptor
负责权限校验的过滤器,负责授权
执行访问控制决策,确定当前用户是否有权访问请求的资源。
认证流程
Authentication
Authentication
类是一个核心接口,表示用户的认证信息,有如下的方法
- **
getAuthorities()
**:返回用户的权限(角色)。 - **
getCredentials()
**:返回用户的凭证(如密码)。 - **
getDetails()
**:返回与认证请求相关的附加信息。 - **
getPrincipal()
**:返回用户的主体信息(如用户名)。 - **
isAuthenticated()
**:返回用户是否已认证。 - **
setAuthenticated(boolean isAuthenticated)
**:设置用户的认证状态。
SecurityContextHolder
SecurityContextHolder
是 Spring Security 中的一个核心类,用于存储和获取当前应用程序的安全上下文(SecurityContext
包含了当前用户的认证信息 Authentication
对象)
主要作用为:
- 存储认证信息:
SecurityContextHolder
存储当前用户的SecurityContext
,其中包含了用户的认证信息和权限。 - 获取认证信息:可以通过
SecurityContextHolder
获取当前用户的SecurityContext
,从而获取用户的认证信息和权限。 - 线程安全:
SecurityContextHolder
提供了多种策略来确保在多线程环境中安全地存储和访问SecurityContext
。
项目配置
1 | <dependency> |
添加项目配置后重新运行项目
产生一个 security password
如果此时直接访问这个应用会出现 401 错误
基于表单的登陆和登出
Security 提供了两个界面用于登陆和登出,分别位于 /login 和 /logout 路径下
只有通过这个进行验证后才能访问服务的其他端点
禁用 Spring Security
1 |
CSRF
验证码验证
Security + JWT 实现用户权限控制
登陆
- 自定义登陆接口
- 调用 ProviderManger 的方法进行验证 如果验证通过生成 JWT
- 将用户信息存入 Redis 中(减少存储压力)
- 自定义
UserDetailService
- 实现查询数据库获得数据
校验
定义 JWT 认证过滤器
- 获取 token
- 解析 token 获取其中的 UserId
- 从 redis 中获取用户信息
- 存入 SecurityContextHolder
无法自动装配。找不到 ‘HttpSecurity’ 类型的 Bean。
1 | //启动类添加注解 |
java: java.lang.NoSuchFieldError
1 | Class com.sun.tools.javac.tree.JCTree$JCImport does not have member field 'com.sun.tools.javac.tree.JCTree qualid' |
数据库校验用户
实现 UserDetailsService
接口
实现 UserDetails
接口
密码加密存储
在实际项目中不会将密码等重要数据以明文的形式存入数据库中。
默认的 PasswordEncoder 要求数据库中的密码格式为:{id} password。会自动根据 id 的值去判断数据库中密码的加密方式。但是我们不会使用这种形式进行存储。所以需要替换这个 PasswordEncoder。
可以使用 SpringScurity 提供的 BCryptPasswordEncoder。需要将 BCryptPasswordEncoder 对象注入 Spring 容器中,SpringScurity 就会使用该种形式的 PasswordEncoder 进行密码校验。
定义一个 SpringScurity 的配置类
1 | package com.wcx.blog.BlogBackend.config; |
接口放行
1 |
|
装载 AuthenticationManager
暴露出 AuthenticationManager 用于验证
1 | // JwtSecurityConfig |
实现登陆验证逻辑
1 | public String login(String phone,String password){ |
JWT 认证过滤器
OncePerRequestFilter 是 Spring Framework 提供的一个抽象类,它用于确保一个请求只被过滤一次。
1 |
|
配置 设置过滤器的位置
1 | // JwtSecurityConfig securityFilterChain |
Cannot invoke “org.apache.commons.logging.Log.isDebugEnabled ()” because “this.logger” is null 问题解决
参考链接 StackoverFlow
出现的原因,使用 AOP + logger 时将一些不正确的类也包括了进去,导致报错。具体来说是因为 GenericFilterBean 是 Spring 提供的一个基础类,用于创建过滤器。它在初始化时会设置 logger 对象。如果在 logger 对象被设置之前就调用了需要使用 logger 的方法,就会出现这个问题。 不一定是直接使用这个类,可能是继承了这个类或者其子类
1 | @Around("execution(* com.wcx.blog.BlogBackend..*(..)) |
修改后
1 | @Around("execution(* com.wcx.blog.BlogBackend..*(..)) && !execution(* com.wcx.blog.BlogBackend.config.JwtAuthenticationTokenFilter.*(..))") |
- 添加 Spring Security 和 JWT 相关的依赖。
- 创建一个 JwtTokenProvider 类,用于生成和验证 JWT。
- 创建一个 JwtAuthenticationFilter 类,用于在每个请求中获取 JWT,并进行验证。
- 在 Spring Security 的配置类中,配置 JwtAuthenticationFilter。
- 创建一个 UserDetailsService 实现类,用于加载用户信息。
- 在 Spring Security 的配置类中,配置 UserDetailsService 和密码编码器。
1 | /* |
第三方登录
Todo
- 使用 Security 和 JWT 实现用户权限限制
- 实现 OAuth2 实现使用 github 账号登陆