技术文章
211学长带你零基础玩转Spring Security认证
大家好,我是你们的后端讲师,也是一名在读的211计算机专业研究生。平时在实验室做科研,也经常带学弟学妹们做项目。我当初学Spring Security的时候,被各种过滤器和配置类搞得晕头转向,看官方文档就像看天书,踩了无数坑。所以今天特意写了这篇教程,希望能帮完全零基础的新人快速跨过这道门槛。
在当前的AI浪潮下,我们写代码不能只局限于传统的CRUD,还要具备技术前瞻思维。比如现在非常火热的智能体开发,当多个智能体(Agent)需要进行协作,或者智能体需要调用外部敏感API时,接口安全是重中之重。熟练掌握Java生态中最权威的Spring Security,不仅能保护你的常规Web应用,未来也能为你的智能体服务构建坚固的安全屏障。
环境准备
工欲善其事,必先利其器。为了跟上最新的技术栈,我们采用Spring Boot 3.x版本。
- JDK 17及以上:这是Spring Boot 3的硬性要求,千万别用JDK 8了。
- Maven 3.6及以上:用于依赖管理。
- IDEA 2023及以上:推荐开发工具。
在IDEA中使用Spring Initializr创建一个新项目,打包方式选择Jar,Java版本选择17。在依赖选择界面,务必勾选Spring Web和Spring Security。
核心概念
很多新手一上来就看源码,结果直接劝退。我当初学的时候也是,后来发现先用大白话理解核心概念最重要。
- 认证(Authentication):解决“你是谁”的问题。就像进小区,保安要查你的门禁卡,确认你是业主。
- 授权(Authorization):解决“你能干嘛”的问题。确认你是业主后,保安还要看你能不能进地下车库,或者能不能使用会所。
- SecurityContext(安全上下文):相当于保安室的登记册。用户登录成功后,他的身份信息会被存放在这里,后续请求都可以从这里获取当前用户信息。
- FilterChain(过滤器链):相当于进大楼的安检门。HTTP请求进来后,会经过一系列过滤器(如用户名密码校验过滤器、异常处理过滤器等),一关一关检查,全部通过才能到达你的Controller。
实战项目
光说不练假把式,我们直接动手搭建一个最简单的安全认证系统。
步骤一:配置安全规则
在Spring Boot 3中,我们不再使用继承WebSecurityConfigurerAdapter的老旧写法,而是采用组件化的配置方式。新建一个配置类:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// 配置安全过滤器链
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// 授权配置
.authorizeHttpRequests(auth -> auth
// 允许公开访问的接口
.requestMatchers("/public/**").permitAll()
// 其他所有请求都需要认证
.anyRequest().authenticated()
)
// 开启表单登录(Spring Security会提供默认登录页)
.formLogin(form -> form.permitAll())
// 开启登出
.logout(logout -> logout.permitAll());
return http.build();
}
// 配置基于内存的用户信息(适合入门测试)
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("admin")
.password("123456")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
步骤二:编写测试接口
新建一个Controller,用来验证我们的安全配置是否生效。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
// 公开接口,无需登录即可访问
@GetMapping("/public/hello")
public String publicHello() {
return "Hello, 这是一个公开接口!";
}
// 受保护接口,必须登录后才能访问
@GetMapping("/private/hello")
public String privateHello() {
return "Hello, 尊贵的已登录用户!";
}
}
步骤三:运行与测试流程
启动项目后,我们按照以下文字流程进行测试:
- 访问公开接口:在浏览器输入
http://localhost:8080/public/hello,页面直接显示“Hello, 这是一个公开接口!”,说明放行配置生效。 - 访问受保护接口:输入
http://localhost:8080/private/hello,页面会自动跳转到Spring Security默认的登录页面。 - 执行登录:在登录页输入用户名
admin和密码123456,点击登录。 - 验证结果:登录成功后,页面会自动重定向回
/private/hello,并显示“Hello, 尊贵的已登录用户!”。
常见问题
新手在实战中极易遇到以下问题,我为大家整理了避坑指南:
| 常见问题 | 产生原因 | 解决方案 |
|---|---|---|
启动报错 Encoded password does not look like BCrypt |
Spring Security 5.x 之后默认要求密码必须加密,而我们配置了明文密码。 | 使用 User.withDefaultPasswordEncoder()(仅限测试),或注入 PasswordEncoder Bean 对密码进行加密。 |
访问接口返回 403 Forbidden |
可能是CSRF防护拦截了POST请求,或者当前用户没有对应接口的权限。 | 如果是前后端分离或使用Token,可在配置中调用 .csrf(csrf -> csrf.disable()) 关闭CSRF。 |
启动报错 BeanCurrentlyInCreationException |
循环依赖问题,通常是因为在Security配置类中注入了依赖Security上下文的Bean。 | 检查Bean的注入关系,必要时使用 @Lazy 注解延迟加载,或将配置类拆分。 |
学习建议与避坑指南
对于零基础的同学,我的建议是先跑通,再深究。不要一开始就死磕源码里的几十个过滤器,先按照上面的步骤把系统跑起来,有直观感受后,再去研究 UsernamePasswordAuthenticationFilter 等核心过滤器的执行顺序。
下一步学习路径建议:
- 自定义登录逻辑:将基于内存的用户,替换为从MySQL数据库中读取用户信息(实现
UserDetailsService接口)。 - 前后端分离鉴权:学习使用JWT(JSON Web Token)替代传统的Session,实现无状态认证。
- 结合智能体开发:在你的智能体应用中,尝试为Agent的API调用集成OAuth2.0协议,实现跨服务的安全授权。
编程是一场马拉松,Spring Security只是其中的一个补给站。保持好奇心,多动手敲代码,遇到报错不要慌,看懂控制台的异常堆栈,你就已经超越了80%的新手。祝大家学习顺利,我们下篇博客见!

评论 0