Spring Security面试题
2026/1/15大约 4 分钟SpringSpring SecurityJava安全认证授权
Spring Security面试题
基础概念
1. Spring Security 的核心组件有哪些?
答案:
| 组件 | 作用 |
|---|---|
| SecurityContextHolder | 存储当前安全上下文 |
| SecurityContext | 包含 Authentication 对象 |
| Authentication | 认证信息(用户、凭证、权限) |
| AuthenticationManager | 认证管理器 |
| AuthenticationProvider | 认证提供者 |
| UserDetailsService | 加载用户信息 |
| UserDetails | 用户详情 |
| GrantedAuthority | 权限 |
2. Authentication 和 Authorization 有什么区别?
答案:
| 特性 | Authentication(认证) | Authorization(授权) |
|---|---|---|
| 目的 | 验证身份 | 验证权限 |
| 问题 | 你是谁? | 你能做什么? |
| 时机 | 先执行 | 后执行 |
| 失败结果 | 401 Unauthorized | 403 Forbidden |
3. Spring Security 的过滤器链是如何工作的?
答案:
Spring Security 通过一系列过滤器处理请求:
主要过滤器:
- SecurityContextPersistenceFilter:加载/保存 SecurityContext
- UsernamePasswordAuthenticationFilter:处理表单登录
- ExceptionTranslationFilter:处理安全异常
- FilterSecurityInterceptor:授权决策
认证相关
4. Spring Security 的认证流程是怎样的?
答案:
- 用户提交用户名密码
UsernamePasswordAuthenticationFilter创建UsernamePasswordAuthenticationTokenAuthenticationManager委托给AuthenticationProviderAuthenticationProvider调用UserDetailsService加载用户信息- 验证密码是否匹配
- 认证成功,创建已认证的
Authentication对象 - 存储到
SecurityContextHolder
5. 如何自定义 UserDetailsService?
答案:
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
return org.springframework.security.core.userdetails.User.builder()
.username(user.getUsername())
.password(user.getPassword())
.roles(user.getRoles().toArray(new String[0]))
.build();
}
}6. Spring Security 支持哪些密码加密方式?
答案:
| 实现 | 说明 | 推荐度 |
|---|---|---|
| BCryptPasswordEncoder | BCrypt 算法,自带盐值 | 推荐 |
| Argon2PasswordEncoder | Argon2 算法 | 推荐 |
| SCryptPasswordEncoder | SCrypt 算法 | 推荐 |
| Pbkdf2PasswordEncoder | PBKDF2 算法 | 一般 |
| NoOpPasswordEncoder | 不加密 | 仅测试 |
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}授权相关
7. @PreAuthorize 和 @PostAuthorize 有什么区别?
答案:
| 注解 | 执行时机 | 用途 |
|---|---|---|
| @PreAuthorize | 方法执行前 | 检查是否有权限执行 |
| @PostAuthorize | 方法执行后 | 检查是否有权限返回结果 |
// 执行前检查
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long id) { }
// 执行后检查
@PostAuthorize("returnObject.owner == authentication.name")
public Document getDocument(Long id) { }8. hasRole 和 hasAuthority 有什么区别?
答案:
hasRole("ADMIN"):检查是否有ROLE_ADMIN权限(自动加 ROLE_ 前缀)hasAuthority("ADMIN"):检查是否有ADMIN权限(不加前缀)
// 以下两种写法等价
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/admin/**").hasAuthority("ROLE_ADMIN")9. 如何实现自定义的权限检查逻辑?
答案:
@Component("permissionChecker")
public class PermissionChecker {
public boolean canAccess(Long resourceId) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
// 自定义权限检查逻辑
return checkPermission(auth.getName(), resourceId);
}
}
// 使用
@PreAuthorize("@permissionChecker.canAccess(#id)")
public Resource getResource(Long id) { }JWT 相关
10. JWT 认证和 Session 认证有什么区别?
答案:
| 特性 | JWT | Session |
|---|---|---|
| 存储位置 | 客户端 | 服务端 |
| 状态 | 无状态 | 有状态 |
| 扩展性 | 易于水平扩展 | 需要 Session 共享 |
| 安全性 | Token 泄露风险 | Session 劫持风险 |
| 注销 | 较复杂 | 简单 |
| 适用场景 | 分布式、前后端分离 | 传统 Web 应用 |
11. JWT 的结构是怎样的?
答案:
JWT 由三部分组成,用 . 分隔:
- Header:算法和类型
{
"alg": "HS256",
"typ": "JWT"
}- Payload:数据载荷
{
"sub": "user123",
"name": "John",
"roles": ["USER"],
"exp": 1516239022
}- Signature:签名
HMACSHA256(base64(header) + "." + base64(payload), secret)12. 如何实现 JWT Token 的刷新机制?
答案:
双 Token 机制
- Access Token:短期有效(如 15 分钟)
- Refresh Token:长期有效(如 7 天)
刷新流程
@PostMapping("/refresh")
public ResponseEntity<?> refresh(@RequestBody RefreshRequest request) {
String refreshToken = request.getRefreshToken();
// 验证 Refresh Token
if (!jwtUtils.validateRefreshToken(refreshToken)) {
return ResponseEntity.status(401).body("Refresh Token 无效");
}
// 生成新的 Access Token
String username = jwtUtils.getUsername(refreshToken);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
String newAccessToken = jwtUtils.generateAccessToken(userDetails);
return ResponseEntity.ok(new TokenResponse(newAccessToken, refreshToken));
}安全防护
13. Spring Security 如何防止 CSRF 攻击?
答案:
Spring Security 默认启用 CSRF 保护:
- 生成 Token:服务端生成 CSRF Token
- 存储 Token:存储在 Session 或 Cookie 中
- 验证 Token:每次请求验证 Token
// 禁用 CSRF(如 JWT 认证)
http.csrf(csrf -> csrf.disable());
// 自定义 CSRF Token 存储
http.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);14. 如何防止暴力破解?
答案:
- 登录失败限制
@Component
public class LoginAttemptService {
private final LoadingCache<String, Integer> attemptsCache;
public LoginAttemptService() {
attemptsCache = CacheBuilder.newBuilder()
.expireAfterWrite(15, TimeUnit.MINUTES)
.build(new CacheLoader<>() {
public Integer load(String key) { return 0; }
});
}
public void loginFailed(String ip) {
int attempts = attemptsCache.getUnchecked(ip);
attemptsCache.put(ip, attempts + 1);
}
public boolean isBlocked(String ip) {
return attemptsCache.getUnchecked(ip) >= 5;
}
}- 验证码
- 账户锁定
15. Spring Security 6.x 有哪些重要变化?
答案:
- 配置方式变化
// 旧版本
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
// 新版本
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
)- 方法安全注解
// 旧版本
@EnableGlobalMethodSecurity(prePostEnabled = true)
// 新版本
@EnableMethodSecurity- 移除 WebSecurityConfigurerAdapter
// 旧版本
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter { }
// 新版本
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) { }
}小结
本章汇总了 Spring Security 相关的常见面试题,涵盖核心概念、认证授权、JWT、安全防护等方面。掌握这些知识点有助于深入理解 Spring Security 的设计原理和最佳实践。
