news 2026/3/30 19:40:53

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/3/27 12:54:08

计算机毕业设计springboot图书在线借阅系统 基于SpringBoot的智慧图书馆借阅服务平台 高校数字化图书借还管理系统的设计与实现

计算机毕业设计springboot图书在线借阅系统v6fh70kc &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。 随着信息技术的飞速发展和移动互联网的普及&#xff0c;传统图书馆管理模式…

作者头像 李华
网站建设 2026/3/27 20:14:15

计算机毕业设计springboot高校毕业生就业岗位推荐系统 基于SpringBoot的高校毕业生求职智能匹配服务平台 高校毕业生就业职位精准推荐与管理系统

计算机毕业设计springboot高校毕业生就业岗位推荐系统dym6tr30 &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。随着高等教育规模持续扩大&#xff0c;每年数百万毕业生涌入就业市…

作者头像 李华
网站建设 2026/3/26 21:56:07

数据加密测试全流程精解:从原理到GDPR合规实战

随着金融科技与医疗 SaaS 的爆发式增长&#xff0c;2026年全球数据泄露成本已攀升至 480 万美元/起。本文深度拆解加密测试八大核心环节&#xff0c;结合AI驱动的新型测试工具链&#xff0c;助您构建符合ISO 27001与GDPR新规的防御体系。 一、加密测试核心流程框架 1. 需求分析…

作者头像 李华
网站建设 2026/3/26 22:54:34

机械制造行业,SpringMVC如何支持百M大文件的下载安全性?

大型文件传输系统解决方案 项目需求分析 作为江苏某上市集团公司的项目负责人&#xff0c;我深知当前面临的文件传输需求具有以下关键挑战&#xff1a; 超大文件传输&#xff1a;需支持50G文件及100G文件夹高可靠性&#xff1a;需实现断点续传&#xff0c;且刷新/重启浏览器…

作者头像 李华
网站建设 2026/3/26 13:10:57

开发抢红包软件违法

“抢红包软件是否违法”这个问题&#xff0c;答案不能一概而论。软件本身是一个工具&#xff0c;具体是否违法&#xff0c;完全取决于“谁在用”以及“用这个软件来干什么”。 为了让你快速理解&#xff0c;我把几种典型情况整理成了下表&#xff1a; 违法场景主要行为描述可…

作者头像 李华