请写一篇关于【Spring Security基础:快速搭建安全认证系统】的技术文章
去年十月的一个周五晚上,我正窝在越秀老城区那套月租3500的单间里,左手拿着肠粉,右手敲着键盘。微信突然“叮”一声——是我刚相亲认识不到一个月的阿琳发来的消息:“你那个系统能不能加个登录?现在谁还做裸奔网站啊?”
我当时差点把肠粉掉地上。
不是因为她说得不对,而是……我确实还没给我的小项目加认证。作为一个写了五年Java的老广程序员,Spring Boot用得飞起,但一提到 Spring Security,我就头皮发麻。总觉得它像西门口那家开了三十年的牛杂店——东西是好,但汤底太浓、料太多,新手根本不知道从哪下嘴。
更尴尬的是,阿琳不是随便问问。她是个Python后端,在一家做区块链数据追踪的小公司上班,虽然天天吐槽他们链上解析慢得像珠江退潮,但人家对安全这事门儿清。“你们Java系不是号称企业级安全扛把子吗?怎么连个Basic Auth都不配?”她调侃道。
我只能苦笑。是啊,GitHub上随便搜个开源项目,十个有八个都写着“Spring Security集成中”,结果点进去发现configure(HttpSecurity http)里就一行.permitAll()——纯属精神胜利法。
一、为什么我拖到相亲对象都看不下去了才学 Spring Security?
说实话,不是我不想学,是以前被吓怕了。
2019年我在天河某外包公司,接了个政府OA系统改造活儿。老板拍胸脯说“用Spring Security,安全第一!”结果文档翻三天,光UserDetailsService、PasswordEncoder、AuthenticationManager这几个类的关系就把我绕晕。最后硬着头皮抄了个CSDN教程,结果上线第二天就被渗透测试打穿——密码居然明文存数据库!
那次之后,我看到“Security”三个字就PTSD。宁愿手动写个拦截器+Session判断,也不敢碰这个“企业级怪兽”。
直到今年年初,我跳槽到了一家做SaaS的创业公司,月薪从15k涨到22k(广州老城区程序员的天花板了),老板明确要求所有新接口必须带RBAC权限控制。HR面谈时还特意问:“会Spring Security吗?”我硬着头皮点头,心里却在默念:“佛祖保佑,别让我现场写配置。”
回家跟阿琳吐槽,她直接甩给我一个链接:“你看这个GitHub仓库,就三百行代码,跑起来再说。”
那是我第一次认真看一个叫 spring-security-demo 的极简示例。
二、别被吓住!Spring Security 其实就三步
我花了整整一个周末(牺牲了和阿琳去北京路喝糖水的时间),终于搞明白:Spring Security 的核心逻辑其实特别简单,复杂的是它的扩展性和企业级场景。但对我们这种只想“先能登录”的人来说,三步就能跑通:
第一步:加依赖,别整花活
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
就这一行!不用额外引入Web、OAuth2那些乱七八糟的。很多人一上来就想搞JWT、搞OAuth2.0,结果连最基本的表单登录都没跑通,纯属自虐。
第二步:写个最简单的配置类
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.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.builder()
.username("user")
.password("{noop}123456") // 注意:{noop}表示不加密,仅演示!
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
看到没?就两个Bean:
SecurityFilterChain:管“哪些路径要认证”UserDetailsService:管“用户存在不存在”
重点来了:那个 {noop}123456 是为了演示方便。真实项目必须用 PasswordEncoder 加密!比如:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
然后存密码时用 passwordEncoder.encode("123456") —— 这步千万别省,否则阿琳又要骂我“裸奔程序员”了。
第三步:写个登录页(可选)
如果你不想用Spring Security默认那个丑到爆的登录框(真的,蓝白配色像90年代网吧),就自己写个 /login.html,表单提交到 /login 即可。记住字段名必须是 username 和 password,除非你重写。
三、实战:给我的“相亲记录管理系统”加上认证
说到这个系统,其实是被逼出来的。
自从开始相亲,我妈每周打电话查岗:“今天见了几个?对方做什么的?月薪多少?有没有房?” 我烦得不行,干脆用Spring Boot写了个小工具,记录每次相亲的时间、地点、对方职业、是否继续接触等信息。前端用Thymeleaf,后端就几个CRUD接口。
但问题来了——这玩意儿要是被人黑了,把我“备注:长得像周杰伦但秃头”的记录泄露出去,我在老城区亲戚圈就彻底社死了。
所以必须加登录!
我按上面三步走,15分钟搞定。访问 /records 时自动跳转到 /login,输对账号密码才能进。阿琳看了直摇头:“这也太简陋了吧?连注册都没有。”
我说:“够用就行。我又不是做社交APP,就我和我妈两个人用(我妈账号我帮她登)。”
她翻白眼:“你这思想危险了啊。现在连区块链钱包都讲究最小权限原则,你一个管理个人隐私数据的系统,居然只靠一个共享密码?”
我愣住。她说得对。于是我加了角色区分:
// 管理员(我)可以删记录,普通用户(我妈)只能看
.requestMatchers("/records/delete").hasRole("ADMIN")
.requestMatchers("/records/**").hasAnyRole("ADMIN", "USER")
顺便把用户存到数据库,而不是内存里——毕竟我妈万一哪天学会自己登,我还得给她单独建账号。
四、Spring Security vs Python + 区块链?别搞混了!
这里必须澄清一个误区:Spring Security 不是万能的安全方案,尤其别拿它和区块链瞎比。
阿琳他们公司做区块链浏览器,经常要验证交易签名、防止重放攻击,那套安全模型是基于密码学+共识机制的,和Web应用的“认证授权”根本不是一个维度。
而Python生态里,Django自带的Auth系统、Flask-Security这些,其实思路和Spring Security高度相似:都是拦截请求 → 验证身份 → 检查权限。
区别在于:
- Java系(尤其是Spring)喜欢“配置即代码”,用Bean和注解织成一张网;
- Python系更倾向“显式优于隐式”,很多逻辑写在视图函数里。
但底层思想一致:认证(你是谁) + 授权(你能干啥)。
所以别听风就是雨,说什么“区块链让传统认证过时了”。除非你的系统真要上链(比如要做去中心化身份DID),否则老老实实用Spring Security,比自己造轮子安全一百倍。
五、GitHub 上那些“完美示例”,其实都在骗你
我早期踩的坑,很大程度上是因为看了太多GitHub上的“最佳实践”项目。
比如某个Star 8k+的仓库,一上来就集成:
- JWT
- OAuth2
- Redis存Token
- 自定义异常处理器
- 多租户支持
- ……
新手照着抄,结果连401错误都调试半天——因为漏了一个CORS配置,或者忘了加@EnableGlobalMethodSecurity。
后来我才明白:学习任何框架,都要从“最小可运行单元”开始。
就像学做云吞面,先学会煮面、调汤、包馅,再考虑加叉烧还是炸酱。Spring Security也一样:
- 先跑通表单登录(Form Login)
- 再试HTTP Basic(适合API)
- 然后加数据库用户
- 最后考虑Token、OAuth2这些高级货
GitHub上有不少良心项目,比如 spring-guides/gs-securing-web,官方出品,代码干净,注释详细。建议新手从这种入手,别一上来就啃大厂开源项目的security模块——那都是经过三年五载打磨的产物,不适合初学者。
六、脱单之后,我对“安全”的理解变了
说来有点矫情,但确实是事实:谈恋爱让我更重视“边界感”。
以前写代码,总觉得“能跑就行”,权限控制?加个if判断呗。但现在不一样了。阿琳常说:“你愿意把聊天记录给我看,不代表你妈也能看。” —— 这不就是RBAC(基于角色的访问控制)的本质吗?
技术如此,生活亦如此。安全不是枷锁,而是对他人和自己的尊重。
所以当我给相亲系统加上 .hasRole("FAMILY") 和 .hasRole("MYSELF") 时,突然觉得Spring Security也没那么可怕。它不过是在帮我们划清界限:什么数据谁可以碰,什么操作需要确认。
结语:安全不是功能,而是习惯
写这篇文章的时候,阿琳正在厨房煲老火汤(她说程序员肝火旺,要降火)。我回头看自己这一年:从被相亲对象质疑“连登录都没有”,到现在能手写一套基于JWT的无状态认证(当然,还是先跑通了Form Login才敢进阶),最大的收获不是技术,而是心态。
别怕Spring Security。它就像广州的老城区——表面看巷子窄、电线乱,但住久了你会发现,每一块砖都有它的道理。
给新手的三条建议:
- 从最简配置开始:先跑通,再优化。别一上来就想搞分布式Session。
- 密码必须加密:哪怕只是本地玩,也要养成
BCryptPasswordEncoder的习惯。 - 权限粒度要细:不要所有接口都
.authenticated()完事,关键操作(如删除、支付)一定要.hasRole()。
最后,如果你也在广州老城区租房、相亲、写代码,欢迎来GitHub找我(账号就叫oldguang-programmer)。虽然我的代码可能不够优雅,但至少……现在有登录了。
毕竟,连相亲都能成功的人,还有什么技术搞不定呢?

评论 0