news 2026/4/18 7:22:58

Spring Security 从入门到精通:手把手教你构建安全的 Java Web 应用(附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Security 从入门到精通:手把手教你构建安全的 Java Web 应用(附完整代码)

适用人群:Java 后端开发、Spring Boot 初学者、对系统安全一知半解的小白
技术栈:Java 17 + Spring Boot 3.2 + Spring Security + JWT
目标:从零配置登录认证,到实现权限控制,再到生产级安全加固,一步到位!


🔒 一、为什么需要 Spring Security?

想象一下:你的网站有用户注册、后台管理、支付接口……
如果没有安全防护,会发生什么?

  • 任何人都能访问/admin/deleteAllUsers
  • 用户 A 可以冒充用户 B 修改订单
  • 密码明文存储,数据库一泄露,全站崩盘

Spring Security 就是你的“数字保安”,它帮你:

  • 验证用户身份(Authentication)
  • 控制资源访问权限(Authorization)
  • 防御 CSRF、XSS、会话固定等常见攻击

❌ 二、反例:没有安全的系统有多危险?

// ❌ 危险!任何人都能删除用户! @RestController public class UserController { @DeleteMapping("/user/{id}") public String deleteUser(@PathVariable Long id) { userService.delete(id); // 无任何权限校验! return "删除成功"; } }

后果:黑客只需发送一个 DELETE 请求,你的用户数据就没了!


✅ 三、入门:5 分钟实现基础登录认证

步骤 1:创建 Spring Boot 项目

使用 start.spring.io,选择:

  • Spring Web
  • Spring Security
  • Spring Data JPA(可选,用于用户存储)

步骤 2:添加依赖(pom.xml

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>

步骤 3:启动应用,观察默认行为

  • 访问http://localhost:8080/any-path
  • 自动跳转到/login页面
  • 控制台打印一行密码(如Using generated security password: a1b2c3d4...

✅ 这就是 Spring Security 的默认安全策略:所有请求必须认证!


🛠️ 四、自定义用户认证(基于内存)

场景:我们想用自己定义的用户名/密码登录

@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public UserDetailsService userDetailsService() { UserDetails user = User.builder() .username("admin") .password("{noop}123456") // {noop} 表示不加密(仅演示!) .roles("USER", "ADMIN") .build(); return new InMemoryUserDetailsManager(user); } @Bean public SecurityFilterChain filterChain(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(); } }

⚠️ 注意:{noop}表示明文密码绝对不能用于生产环境!


🔐 五、生产级密码加密(必须做!)

反例:明文存密码

// ❌ 千万别这么干! passwordEncoder.encode("123456"); // 如果 encoder 是 NoOpPasswordEncoder

正确做法:使用 BCrypt 加密

@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } // 注册用户时加密 String encodedPassword = passwordEncoder.encode("123456"); UserDetails user = User.builder() .username("admin") .password(encodedPassword) // 存的是加密后的字符串 .roles("ADMIN") .build();

✅ BCrypt 是单向哈希,即使数据库泄露,也无法反推原始密码!


🧩 六、基于角色的权限控制(RBAC)

场景:普通用户只能看自己的订单,管理员能删所有订单

@RestController public class OrderController { // 所有登录用户可访问 @GetMapping("/orders") public List<Order> getOrders(Authentication auth) { String username = auth.getName(); return orderService.findByUser(username); } // 仅 ADMIN 角色可访问 @DeleteMapping("/orders/{id}") @PreAuthorize("hasRole('ADMIN')") // 关键注解! public String deleteOrder(@PathVariable Long id) { orderService.delete(id); return "删除成功"; } }

💡 要启用@PreAuthorize,需在配置类加:

@EnableMethodSecurity // 替代旧版 @EnableGlobalMethodSecurity

🪪 七、JWT 无状态认证(适合前后端分离)

为什么用 JWT?

  • 传统 Session 有状态,不适合分布式
  • JWT 无状态,前端每次携带 Token 即可

实现步骤:

1. 添加 JWT 工具类
@Component public class JwtUtil { private String secret = "MySecretKey123!@#"; // 生产环境用更长的密钥 public String generateToken(String username) { return Jwts.builder() .setSubject(username) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 24小时 .signWith(SignatureAlgorithm.HS512, secret) .compact(); } public String extractUsername(String token) { return Jwts.parser().setSigningKey(secret).parseClaimsJws(token) .getBody().getSubject(); } public boolean validateToken(String token, String username) { String extractedUsername = extractUsername(token); return (extractedUsername.equals(username) && !isTokenExpired(token)); } }
2. 自定义 Filter 拦截 Token
@Component public class JwtAuthFilter extends OncePerRequestFilter { @Autowired private UserDetailsService userDetailsService; @Autowired private JwtUtil jwtUtil; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String header = request.getHeader("Authorization"); String username = null; String jwt = null; if (header != null && header.startsWith("Bearer ")) { jwt = header.substring(7); try { username = jwtUtil.extractUsername(jwt); } catch (Exception e) { // token 无效 } } if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); if (jwtUtil.validateToken(jwt, userDetails.getUsername())) { UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authToken); } } chain.doFilter(request, response); } }
3. 配置 Security 使用 JWT
@Bean public SecurityFilterChain filterChain(HttpSecurity http, JwtAuthFilter jwtFilter) throws Exception { http .csrf(csrf -> csrf.disable()) // JWT 通常禁用 CSRF .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/auth/login").permitAll() .anyRequest().authenticated() ) .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); }
4. 登录接口返回 Token
@PostMapping("/auth/login") public ResponseEntity<?> login(@RequestBody LoginRequest req) { authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(req.getUsername(), req.getPassword()) ); UserDetails user = userDetailsService.loadUserByUsername(req.getUsername()); String token = jwtUtil.generateToken(user.getUsername()); return ResponseEntity.ok(Map.of("token", token)); }

⚠️ 八、安全注意事项(血泪教训!)

风险正确做法
密码明文存储必须用BCryptPasswordEncoder
CSRF 攻击表单提交场景开启 CSRF;JWT 无状态可关闭
敏感信息泄露错误信息不要暴露内部细节(如 SQL)
暴力破解登录失败锁定账户或验证码
Token 泄露设置合理过期时间,支持 Token 黑名单
权限绕过前端隐藏按钮 ≠ 后端无校验!后端必须二次验证

📌 九、总结:Spring Security 核心思想

  1. 认证(Authentication):你是谁? → 登录、Token 验证
  2. 授权(Authorization):你能做什么? → 角色、权限控制
  3. 防御(Defense):防攻击 → CSRF、XSS、会话管理

Spring Security 不是“加个依赖就安全”,而是一套完整的安全体系。理解其原理,才能灵活应对各种场景。


视频看了几百小时还迷糊?关注我,几分钟让你秒懂!(发点评论可以给博主加热度哦)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 18:46:28

Clawdbot背后的技术原理,吴恩达出官方课程了

Datawhale干货 最新&#xff1a;吴恩达 Agent Skill 课程如果你最近刷科技圈&#xff0c;一定见过那只红色龙虾——Clawdbot&#xff08;现已改名 OpenClaw&#xff09;。短短一周&#xff0c;12 万 GitHub stars。增长速度快到离谱&#xff0c;社交平台上到处都是开发者在晒截…

作者头像 李华
网站建设 2026/4/18 3:22:50

AI驱动的下一代邮箱安全架构——多层智能防护与高级威胁过滤机制深度剖析

【精选优质专栏推荐】 《AI 技术前沿》 —— 紧跟 AI 最新趋势与应用《网络安全新手快速入门(附漏洞挖掘案例)》 —— 零基础安全入门必看《BurpSuite 入门教程(附实战图文)》 —— 渗透测试必备工具详解《网安渗透工具使用教程(全)》 —— 一站式工具手册《CTF 新手入门实战教…

作者头像 李华
网站建设 2026/4/1 3:59:20

如何打造工厂大脑实现智能制造升级?

当一名工人对着系统发问&#xff1a;“这台设备为什么报警&#xff1f;”不到一秒时间里&#xff0c;系统不仅翻遍了过去50万次同类故障记录&#xff0c;还结合实时温度、振动、电压曲线&#xff0c;生成了一份带着根因分析的维修方案——这并非科幻电影桥段&#xff0c;而是重…

作者头像 李华
网站建设 2026/4/18 3:33:44

C#与Sql server 2008 R2图书信息管理系统,源码带注释,VS2015版本,.net4

C#与Sql server 2008 R2图书信息管理系统&#xff0c;源码带注释&#xff0c;VS2015版本&#xff0c;.net4.5框架 最近在整理硬盘翻出个古董项目——基于C#和SQL Server 2008 R2的图书管理系统。虽然技术栈有点年头&#xff0c;但架构设计现在看依然有参考价值。随手打开尘封的…

作者头像 李华