springboot-security by affaan-m/everything-claude-code
npx skills add https://github.com/affaan-m/everything-claude-code --skill springboot-security在添加身份验证、处理输入、创建端点或处理密钥时使用。
httpOnly、Secure、SameSite=Strict 的 CookieOncePerRequestFilter 或资源服务器验证令牌@Component
public class JwtAuthFilter extends OncePerRequestFilter {
private final JwtService jwtService;
public JwtAuthFilter(JwtService jwtService) {
this.jwtService = jwtService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (header != null && header.startsWith("Bearer ")) {
String token = header.substring(7);
Authentication auth = jwtService.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
@EnableMethodSecurity@PreAuthorize("hasRole('ADMIN')") 或 @PreAuthorize("@authz.canEdit(#id)")@RestController
@RequestMapping("/api/admin")
public class AdminController {
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/users")
public List<UserDto> listUsers() {
return userService.findAll();
}
@PreAuthorize("@authz.isOwner(#id, authentication)")
@DeleteMapping("/users/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
}
@Valid 的 Bean Validation@NotBlank、@Email、@Size、自定义验证器// 错误示例:无验证
@PostMapping("/users")
public User createUser(@RequestBody UserDto dto) {
return userService.create(dto);
}
// 正确示例:已验证的 DTO
public record CreateUserDto(
@NotBlank @Size(max = 100) String name,
@NotBlank @Email String email,
@NotNull @Min(0) @Max(150) Integer age
) {}
@PostMapping("/users")
public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserDto dto) {
return ResponseEntity.status(HttpStatus.CREATED)
.body(userService.create(dto));
}
:param 绑定;切勿拼接字符串// 错误示例:原生查询中的字符串拼接
@Query(value = "SELECT * FROM users WHERE name = '" + name + "'", nativeQuery = true)
// 正确示例:参数化的原生查询
@Query(value = "SELECT * FROM users WHERE name = :name", nativeQuery = true)
List<User> findByName(@Param("name") String name);
// 正确示例:Spring Data 派生查询(自动参数化)
List<User> findByEmailAndActiveTrue(String email);
PasswordEncoder bean,而非手动哈希@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // 成本因子 12
}
// 在服务中
public User register(CreateUserDto dto) {
String hashedPassword = passwordEncoder.encode(dto.password());
return userRepository.save(new User(dto.email(), hashedPassword));
}
http
.csrf(csrf -> csrf.disable())
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
application.yml 不包含凭据;使用占位符# 错误示例:硬编码在 application.yml 中
spring:
datasource:
password: mySecretPassword123
# 正确示例:环境变量占位符
spring:
datasource:
password: ${DB_PASSWORD}
# 正确示例:Spring Cloud Vault 集成
spring:
cloud:
vault:
uri: https://vault.example.com
token: ${VAULT_TOKEN}
http
.headers(headers -> headers
.contentSecurityPolicy(csp -> csp
.policyDirectives("default-src 'self'"))
.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)
.xssProtection(Customizer.withDefaults())
.referrerPolicy(rp -> rp.policy(ReferrerPolicyHeaderWriter.ReferrerPolicy.NO_REFERRER)));
*@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("https://app.example.com"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
config.setAllowedHeaders(List.of("Authorization", "Content-Type"));
config.setAllowCredentials(true);
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", config);
return source;
}
// 在 SecurityFilterChain 中:
http.cors(cors -> cors.configurationSource(corsConfigurationSource()));
// 使用 Bucket4j 进行每端点速率限制
@Component
public class RateLimitFilter extends OncePerRequestFilter {
private final Map<String, Bucket> buckets = new ConcurrentHashMap<>();
private Bucket createBucket() {
return Bucket.builder()
.addLimit(Bandwidth.classic(100, Refill.intervally(100, Duration.ofMinutes(1))))
.build();
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String clientIp = request.getRemoteAddr();
Bucket bucket = buckets.computeIfAbsent(clientIp, k -> createBucket());
if (bucket.tryConsume(1)) {
chain.doFilter(request, response);
} else {
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
response.getWriter().write("{\"error\": \"Rate limit exceeded\"}");
}
}
}
请记住:默认拒绝、验证输入、最小权限、优先通过配置确保安全。
每周安装数
1.1K
仓库
GitHub 星标数
72.1K
首次出现
Jan 30, 2026
安全审计
安装于
opencode880
codex854
gemini-cli838
github-copilot778
cursor721
kimi-cli718
Use when adding auth, handling input, creating endpoints, or dealing with secrets.
Prefer stateless JWT or opaque tokens with revocation list
Use httpOnly, Secure, SameSite=Strict cookies for sessions
Validate tokens with OncePerRequestFilter or resource server
@Component public class JwtAuthFilter extends OncePerRequestFilter { private final JwtService jwtService;
public JwtAuthFilter(JwtService jwtService) { this.jwtService = jwtService; }
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String header = request.getHeader(HttpHeaders.AUTHORIZATION); if (header != null && header.startsWith("Bearer ")) { String token = header.substring(7); Authentication auth = jwtService.authenticate(token); SecurityContextHolder.getContext().setAuthentication(auth); } chain.doFilter(request, response); } }
Enable method security: @EnableMethodSecurity
Use @PreAuthorize("hasRole('ADMIN')") or @PreAuthorize("@authz.canEdit(#id)")
Deny by default; expose only required scopes
@RestController @RequestMapping("/api/admin") public class AdminController {
@PreAuthorize("hasRole('ADMIN')") @GetMapping("/users") public List<UserDto> listUsers() { return userService.findAll(); }
@PreAuthorize("@authz.isOwner(#id, authentication)") @DeleteMapping("/users/{id}") public ResponseEntity<Void> deleteUser(@PathVariable Long id) { userService.delete(id); return ResponseEntity.noContent().build(); } }
Use Bean Validation with @Valid on controllers
Apply constraints on DTOs: @NotBlank, @Email, @Size, custom validators
Sanitize any HTML with a whitelist before rendering
// BAD: No validation @PostMapping("/users") public User createUser(@RequestBody UserDto dto) { return userService.create(dto); }
// GOOD: Validated DTO public record CreateUserDto( @NotBlank @Size(max = 100) String name, @NotBlank @Email String email, @NotNull @Min(0) @Max(150) Integer age ) {}
@PostMapping("/users") public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserDto dto) { return ResponseEntity.status(HttpStatus.CREATED) .body(userService.create(dto)); }
Use Spring Data repositories or parameterized queries
For native queries, use :param bindings; never concatenate strings
// BAD: String concatenation in native query @Query(value = "SELECT * FROM users WHERE name = '" + name + "'", nativeQuery = true)
// GOOD: Parameterized native query @Query(value = "SELECT * FROM users WHERE name = :name", nativeQuery = true) List<User> findByName(@Param("name") String name);
// GOOD: Spring Data derived query (auto-parameterized) List<User> findByEmailAndActiveTrue(String email);
Always hash passwords with BCrypt or Argon2 — never store plaintext
Use PasswordEncoder bean, not manual hashing
@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(12); // cost factor 12 }
// In service public User register(CreateUserDto dto) { String hashedPassword = passwordEncoder.encode(dto.password()); return userRepository.save(new User(dto.email(), hashedPassword)); }
For browser session apps, keep CSRF enabled; include token in forms/headers
For pure APIs with Bearer tokens, disable CSRF and rely on stateless auth
http .csrf(csrf -> csrf.disable()) .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
No secrets in source; load from env or vault
Keep application.yml free of credentials; use placeholders
Rotate tokens and DB credentials regularly
spring: datasource: password: mySecretPassword123
spring: datasource: password: ${DB_PASSWORD}
spring: cloud: vault: uri: https://vault.example.com token: ${VAULT_TOKEN}
http
.headers(headers -> headers
.contentSecurityPolicy(csp -> csp
.policyDirectives("default-src 'self'"))
.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)
.xssProtection(Customizer.withDefaults())
.referrerPolicy(rp -> rp.policy(ReferrerPolicyHeaderWriter.ReferrerPolicy.NO_REFERRER)));
Configure CORS at the security filter level, not per-controller
Restrict allowed origins — never use * in production
@Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(List.of("https://app.example.com")); config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE")); config.setAllowedHeaders(List.of("Authorization", "Content-Type")); config.setAllowCredentials(true); config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/api/**", config); return source; }
// In SecurityFilterChain: http.cors(cors -> cors.configurationSource(corsConfigurationSource()));
Apply Bucket4j or gateway-level limits on expensive endpoints
Log and alert on bursts; return 429 with retry hints
// Using Bucket4j for per-endpoint rate limiting @Component public class RateLimitFilter extends OncePerRequestFilter { private final Map<String, Bucket> buckets = new ConcurrentHashMap<>();
private Bucket createBucket() { return Bucket.builder() .addLimit(Bandwidth.classic(100, Refill.intervally(100, Duration.ofMinutes(1)))) .build(); }
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String clientIp = request.getRemoteAddr(); Bucket bucket = buckets.computeIfAbsent(clientIp, k -> createBucket());
if (bucket.tryConsume(1)) {
chain.doFilter(request, response);
} else {
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
response.getWriter().write("{\"error\": \"Rate limit exceeded\"}");
}
} }
Remember : Deny by default, validate inputs, least privilege, and secure-by-configuration first.
Weekly Installs
1.1K
Repository
GitHub Stars
72.1K
First Seen
Jan 30, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode880
codex854
gemini-cli838
github-copilot778
cursor721
kimi-cli718
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
AI代码审查工具 - 自动化安全漏洞检测与代码质量分析 | 支持多领域检查清单
1,200 周安装
AI智能体长期记忆系统 - 精英级架构,融合6种方法,永不丢失上下文
1,200 周安装
AI新闻播客制作技能:实时新闻转对话式播客脚本与音频生成
1,200 周安装
Word文档处理器:DOCX创建、编辑、分析与修订痕迹处理全指南 | 自动化办公解决方案
1,200 周安装
React Router 框架模式指南:全栈开发、文件路由、数据加载与渲染策略
1,200 周安装
Nano Banana AI 图像生成工具:使用 Gemini 3 Pro 生成与编辑高分辨率图像
1,200 周安装