一、基础配置示例
1.1 最小化安全配置
@Configuration
@EnableWebSecurity
public class BasicSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
.logout(logout -> logout
.permitAll()
);
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
![图片[1]_Spring Security 完整指南:从入门到实战_知途无界](https://zhituwujie.com/wp-content/uploads/2025/08/d2b5ca33bd20250828110627.png)
1.2 数据库用户存储
@Configuration
public class JdbcSecurityConfig {
@Autowired
private DataSource dataSource;
@Bean
public UserDetailsService userDetailsService() {
JdbcUserDetailsManager userDetailsManager = new JdbcUserDetailsManager(dataSource);
// 自定义查询(如使用现有表结构)
userDetailsManager.setUsersByUsernameQuery(
"SELECT username, password, enabled FROM users WHERE username = ?");
userDetailsManager.setAuthoritiesByUsernameQuery(
"SELECT username, authority FROM authorities WHERE username = ?");
return userDetailsManager;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
二、认证机制详解
2.1 多种认证方式配置
graph TD
A[认证请求] --> B{认证方式}
B --> C[表单登录]
B --> D[JWT认证]
B --> E[OAuth2]
B --> F[Basic认证]
C --> G[Session管理]
D --> H[Token验证]
E --> I[第三方登录]
F --> J[简单认证]
2.2 JWT认证实现
@Component
public class JwtTokenProvider {
private String jwtSecret = "your-secret-key";
private long jwtExpiration = 86400000; // 24小时
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + jwtExpiration))
.signWith(SignatureAlgorithm.HS512, jwtSecret)
.compact();
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
return true;
} catch (Exception ex) {
// 处理各种异常
}
return false;
}
}
@Configuration
@EnableWebSecurity
public class JwtSecurityConfig {
@Autowired
private JwtTokenProvider tokenProvider;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
return http.build();
}
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter(tokenProvider);
}
}
三、授权控制
3.1 方法级安全控制
@Configuration
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class MethodSecurityConfig {
// 方法级安全配置
}
@Service
public class ProductService {
@PreAuthorize("hasRole('ADMIN') or hasAuthority('PRODUCT_WRITE')")
public Product createProduct(Product product) {
// 创建产品逻辑
}
@PostAuthorize("returnObject.owner == authentication.name")
public Product getProduct(Long id) {
// 获取产品逻辑
}
@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
public void deleteProduct(Long id) {
// 删除产品逻辑
}
}
3.2 动态权限控制
@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
@Override
public boolean hasPermission(Authentication authentication,
Object targetDomainObject,
Object permission) {
// 实现自定义权限逻辑
if (targetDomainObject instanceof Product product) {
if ("delete".equals(permission)) {
return product.getOwner().equals(authentication.getName()) ||
authentication.getAuthorities().stream()
.anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"));
}
}
return false;
}
}
四、常见问题解决方案
4.1 密码编码问题
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder() {
// 推荐使用BCrypt
return new BCryptPasswordEncoder();
}
// 解决常见密码编码错误
@Bean
public DaoAuthenticationProvider authenticationProvider(
UserDetailsService userDetailsService,
PasswordEncoder passwordEncoder) {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder);
provider.setHideUserNotFoundExceptions(false); // 重要配置
return provider;
}
}
4.2 CSRF保护配置
@Configuration
public class CsrfConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf
// 禁用CSRF(不推荐生产环境)
// .disable()
// 或配置CSRF token仓库
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// 忽略某些端点
.ignoringRequestMatchers("/api/public/**")
);
return http.build();
}
}
4.3 CORS配置问题
@Configuration
public class CorsConfig {
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", configuration);
return source;
}
}
五、错误处理与调试
5.1 自定义认证失败处理
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
Map<String, Object> body = new HashMap<>();
body.put("timestamp", new Date());
body.put("status", HttpServletResponse.SC_UNAUTHORIZED);
body.put("error", "Unauthorized");
body.put("message", authException.getMessage());
body.put("path", request.getRequestURI());
response.getWriter().write(new ObjectMapper().writeValueAsString(body));
}
}
5.2 访问拒绝处理
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType("application/json");
Map<String, Object> body = new HashMap<>();
body.put("timestamp", new Date());
body.put("status", HttpServletResponse.SC_FORBIDDEN);
body.put("error", "Forbidden");
body.put("message", "Access denied");
body.put("path", request.getRequestURI());
response.getWriter().write(new ObjectMapper().writeValueAsString(body));
}
}
六、实战配置示例
6.1 生产环境安全配置
@Configuration
@EnableWebSecurity
public class ProductionSecurityConfig {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private CustomAuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// 基本配置
.authorizeHttpRequests(auth -> auth
.requestMatchers("/health", "/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/api/**").authenticated()
.anyRequest().denyAll() // 默认拒绝所有
)
// 认证配置
.formLogin(form -> form
.loginPage("/login")
.successHandler(authenticationSuccessHandler())
.failureHandler(authenticationFailureHandler())
.permitAll()
)
// 退出登录
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessHandler(logoutSuccessHandler())
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
)
// 异常处理
.exceptionHandling(exceptions -> exceptions
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
)
// 会话管理
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.maximumSessions(1)
.expiredUrl("/login?expired")
)
// 安全头
.headers(headers -> headers
.contentSecurityPolicy(csp -> csp
.policyDirectives("default-src 'self'")
)
.frameOptions(frame -> frame.sameOrigin())
)
// 记住我
.rememberMe(remember -> remember
.tokenValiditySeconds(86400) // 24小时
.userDetailsService(userDetailsService)
);
return http.build();
}
}
6.2 常见问题排查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 403 Forbidden | CSRF保护启用 | 添加CSRF token或配置忽略 |
| 401 Unauthorized | 认证失败 | 检查密码编码器配置 |
| 登录后重定向循环 | Session配置问题 | 检查session管理配置 |
| 权限注解不生效 | 未启用方法安全 | 添加@EnableMethodSecurity |
| CORS错误 | 跨域配置问题 | 配置CorsConfigurationSource |
七、测试与调试
7.1 安全测试配置
@SpringBootTest
@AutoConfigureMockMvc
public class SecurityTest {
@Autowired
private MockMvc mockMvc;
@Test
@WithMockUser(username = "user", roles = "USER")
public void testAuthenticatedAccess() throws Exception {
mockMvc.perform(get("/api/user"))
.andExpect(status().isOk());
}
@Test
public void testUnauthenticatedAccess() throws Exception {
mockMvc.perform(get("/api/user"))
.andExpect(status().isUnauthorized());
}
@Test
@WithMockUser(username = "user", roles = "USER")
public void testAccessDenied() throws Exception {
mockMvc.perform(get("/api/admin"))
.andExpect(status().isForbidden());
}
}
7.2 调试技巧
@Configuration
public class DebugConfig {
@Bean
public Filter debugFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// 调试信息输出
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
System.out.println("Current user: " + auth.getName());
System.out.println("Authorities: " + auth.getAuthorities());
}
filterChain.doFilter(request, response);
}
};
}
}
这个Spring Security指南涵盖了从基础配置到高级特性的全面内容,包括常见问题的解决方案和最佳实践建议。
© 版权声明
文中内容均来源于公开资料,受限于信息的时效性和复杂性,可能存在误差或遗漏。我们已尽力确保内容的准确性,但对于因信息变更或错误导致的任何后果,本站不承担任何责任。如需引用本文内容,请注明出处并尊重原作者的版权。
THE END

























暂无评论内容