文章目录
- 一、Spring Security 常用应用场景介绍
- 二、Spring Security场景案例
-
- 12 表达式支持(Expression-Based)
-
- 12.1 Spring Security 配置
- 12.2 业务逻辑代码
- 12.3 控制器
- 13、安全上下文(Security Context)
-
- 13.1 Spring Security 配置
- 13.2 业务逻辑代码
- 13.3 控制器
- 14、安全过滤器链(Security Filter Chain)
-
- 14.1 Spring Security 配置
- 14.2 业务逻辑代码
- 14.3 控制器
- 15、用户详细信息服务(UserDetailsService)
-
- 15.1 Spring Security 配置
- 15.2 业务逻辑代码
- 15.3 控制器
- 16、多因素认证(Multi-Factor Authentication)
-
- 16.1 Spring Security 配置
- 16.2 业务逻辑代码
- 16.3 控制器
- 17、匿名访问(Anonymous Access)
-
- 17.1 Spring Security 配置
- 17.2 业务逻辑代码
- 17.3 控制器
Spring Security
通过一系列注解简化了安全配置,我们将深入探讨
Spring Security
框架的17个关键应用场景,包括认证、授权、
OAuth2
、
CSRF
保护等。每个案例都配有详细的时序图和代码示例,旨在帮助开发者全面理解并有效利用
Spring Security
的强大功能,以构建更安全、更可靠的应用程序。
一、Spring Security 常用应用场景介绍
1、认证(Authentication)
- 应用场景:确保只有经过验证的用户才能访问应用程序。
2、授权(Authorization)
- 应用场景:控制用户对特定资源的访问权限,如角色基础的访问控制。
3、表单登录(Form-Based Login)
- 应用场景:为用户提供登录表单,处理登录请求和重定向。
4、HTTP 基本认证(HTTP Basic Authentication)
- 应用场景:为 RESTful API 或其他服务提供基础的用户名和密码认证。
5、OAuth2 和 OpenID Connect
- 应用场景:支持现代的授权框架,适用于需要第三方应用认证的场景。
6、CSRF 保护(CSRF Protection)
- 应用场景:防止跨站请求伪造攻击,保护 Web 应用程序的安全。
7、密码编码(Password Encoding)
- 应用场景:安全地存储用户密码,防止密码泄露。
8、方法级安全性(Method Security)
- 应用场景:控制对特定方法或 Bean 属性的访问,实现细粒度的安全控制。
9、异常处理(Exception Handling)
- 应用场景:自定义安全相关的异常处理,如认证失败、授权失败。
10、记住我(Remember-Me)
- 应用场景:为用户提供持久的登录状态,方便用户再次访问。
11、预授权(Pre-Invocation)
- 应用场景:在方法执行前进行安全检查,确保方法调用的安全性。
12、表达式支持(Expression-Based)
- 应用场景:使用 Spring Expression Language (SpEL) 实现复杂的安全逻辑。
13、安全上下文(Security Context)
- 应用场景:管理和检索认证信息,如获取当前认证用户。
14、安全过滤器链(Security Filter Chain)
- 应用场景:处理 HTTP 请求的安全检查,如认证、授权。
15、用户详细信息服务(UserDetailsService)
- 应用场景:自定义用户认证信息的加载逻辑,如从数据库加载用户数据。
16、多因素认证(Multi-Factor Authentication)
- 应用场景:增加额外的安全层,如短信验证码、电子邮件确认。
17、匿名访问(Anonymous Access)
- 应用场景:允许未认证的用户访问某些公共资源。
二、Spring Security场景案例
12 表达式支持(Expression-Based)
业务场景: 一个在线文档管理系统,其中某些文档的访问权限依赖于用户的多个属性,例如部门和角色。需要使用复杂的表达式来确定用户是否有权访问特定文档。
业务时序图
1.用户(User
) 请求一个资源。
2.浏览器(Browser
) 向服务器(Server
)发送HTTP 请求
。
3.服务器(Server
) 的 认证管理器(AuthenticationManager
) 对请求进行认证。
4.认证管理器(AuthenticationManager
) 返回认证令牌给服务器。
5.服务器(Server
) 的 方法安全拦截器(MethodSecurityInterceptor
) 检查授权。
6.方法安全拦截器(MethodSecurityInterceptor
) 请求 表达式评估器(ExpressionEvaluator
) 处理SpEL 表达式
。
7.表达式评估器(ExpressionEvaluator
) 根据当前的安全上下文和定义的表达式返回评估结果。
8.方法安全拦截器(MethodSecurityInterceptor
) 根据评估结果做出访问决策。
9.服务器(Server
) 将响应返回给浏览器。
12.1 Spring Security 配置
首先,我们需要配置Spring Security
以启用表达式支持。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/documents/**").access("hasRole('ADMIN') or hasAuthority('DOCUMENT_READ')")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/home")
.and()
.logout()
.logoutSuccessUrl("/login?logout");
}
}
12.2 业务逻辑代码
创建一个服务来处理文档访问,并使用表达式来定义访问权限。
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class DocumentService {
/**
* 获取文档内容
*
* @param documentId 文档ID
* @return 文档内容
*/
@PreAuthorize("hasAuthority('DOCUMENT_READ') and #documentId == authentication.principal.departmentId")
public String getDocumentContent(Long documentId) {
// 模拟从数据库获取文档内容
return "Content of the document " + documentId;
}
}
12.3 控制器
创建一个控制器来处理文档访问请求。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DocumentController {
@Autowired
private DocumentService documentService;
@GetMapping("/documents/{documentId}")
public ResponseEntity<String> getDocument(@PathVariable Long documentId) {
return ResponseEntity.ok(documentService.getDocumentContent(documentId));
}
}
说明
- 配置类:配置了
Spring Security
,并启用了方法级安全性,允许使用SpEL表达式
来定义复杂的权限规则。 - 业务逻辑:
DocumentService
提供了获取文档内容的方法,该方法通过@PreAuthorize
注解限制访问权限,使用SpEL表达式
结合用户的角色和属性。 - 控制器:
DocumentController
提供了一个HTTP GET
端点来获取文档内容。
13、安全上下文(Security Context)
业务场景: 一个多租户的SaaS应用程序,需要在每个请求中识别和处理当前认证用户的安全上下文,以确保用户只能访问其租户的数据。
业务时序图
1.用户(User
) 尝试通过浏览器(Browser
)访问一个受保护的资源。
2.浏览器(Browser
) 向服务器(Server
)发送 HTTP 请求
。
3.服务器(Server
) 请求当前的安全上下文( SecurityContextHolder.getContext()
)。
4.安全上下文持有器(SecurityContextHolder
) 提供当前的认证信息。
5.认证(Authentication
) 对象检查用户是否有权访问请求的资源。
6.资源(Resource
) 根据认证信息返回访问决策。
7.认证(Authentication
) 根据需要更新安全上下文。
8.安全上下文持有器(SecurityContextHolder
) 返回更新后的安全上下文。
9.服务器(Server
) 根据安全上下文返回适当的响应给浏览器。
13.1 Spring Security 配置
首先,我们需要配置Spring Security
以确保安全上下文在每个请求中正确处理。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@Ena