请写一篇关于【Spring Security基础:快速搭建安全认证系统】的技术文章
去年十月,我被裁了。
那天是周三,下午三点,刚开完一个需求评审会,HR把我叫进小会议室。她说“公司战略调整”,我点点头,心里却像被人狠狠踹了一脚。六年大厂经验,从Java初级干到后端TL,月薪22k,房租3500,和女朋友合租在浦东金桥——突然之间,一切悬在空中。
回家路上,地铁14号线挤得像沙丁鱼罐头。我盯着手机里猎聘上“急招Spring Security专家”的JD,苦笑。半年前我还觉得Security是“那种老掉牙的框架”,现在?它可能就是我下一份饭碗的关键。
别笑,真有人连Security都配不明白
上个月面试一个候选人,聊到权限控制,他张口就说:“我们用Shiro,轻量。” 我没戳破——其实他们项目根本没做RBAC,用户角色全靠if-else硬编码。这年头,很多所谓“微服务架构”,登录页还是/login?username=admin&password=123456。
我自己也栽过跟头。三年前第一次接手一个遗留系统,前端传token,后端用自定义拦截器校验。结果某次上线,因为漏了@EnableWebSecurity,整个生产环境裸奔了48小时。CTO在晨会上冷笑:“你们这是给黑客发邀请函?”
Spring Security不是银弹,但它是底线。
快速搭个能跑的认证系统?三步走
别被官方文档吓到。我拿上周五晚上熬夜重构的一个demo举例(对,又是周五晚上,女朋友在隔壁打《原神》,我在Terminal里敲代码),核心就三块:
1. 引入依赖 + 启用Security
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
然后主类加注解:
@SpringBootApplication
@EnableWebSecurity
public class AuthApplication {
public static void main(String[] args) {
SpringApplication.run(AuthApplication.class, args);
}
}
搞定。启动项目,访问任意接口,自动跳转到/login,默认用户名user,密码在控制台打印出来。虽然丑,但安全基线有了。
2. 自定义UserDetails + UserDetailsService
真实项目不可能用内存用户。我一般建个UserDetailsServiceImpl:
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
return org.springframework.security.core.userdetails.User
.builder()
.username(user.getUsername())
.password(user.getPassword()) // 记得BCrypt加密!
.roles(user.getRole().split(","))
.build();
}
}
开发心得: 密码千万别明文存!我见过实习生把MD5当“加密”,结果彩虹表一跑全露馅。直接用BCryptPasswordEncoder,Spring Security内置支持,一行配置:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
3. 配置HttpSecurity —— 真正的战场
这才是面试题高频区。比如:“如何放行Swagger和健康检查接口?”
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable() // 前后端分离可关,但要知道风险
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/public/**", "/swagger-ui/**", "/actuator/health").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin().disable() // 用JWT就关掉表单登录
.httpBasic().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
}
面试题挑战来了:
- CSRF为什么能关?
hasRole("ADMIN")和hasAuthority("ROLE_ADMIN")有啥区别?- 如何实现动态权限(比如从数据库读菜单权限)?
答不上来?回去看源码。DefaultWebSecurityExpressionHandler里藏着答案。
别只盯着Java,Go也在抢饭碗
说到这个,我最近在学Go。倒不是想转语言栈,而是发现很多新项目——尤其是云原生、边缘计算场景——直接用Go写Auth服务。Gin + JWT + Casbin,性能吊打Spring Boot。
上周和前同事吃饭,他在一家做IoT的 startup,后端全Go。他说:“你们Java搞个Security配置半小时,我们main.go 50行搞定,还省了JVM内存。”
我嘴上不服:“Go的生态能比Spring全家桶?”
心里却慌了。毕竟裁员名单不分语言。
现实很骨感: 大厂Java岗还在招,但要求越来越高。不仅要你会Security,还要懂OAuth2.0、OIDC、多租户隔离、甚至零信任架构。上周面阿里P7,面试官直接问:“如果让你设计一个支持万级租户的权限中心,怎么保证性能?”
从焦虑到行动:我的自救路线
被裁后那两周,我天天刷LeetCode,但越刷越慌。后来想通了:与其死磕算法,不如把工程能力打扎实。
我做了三件事:
- 重写了一个RBAC demo:用Spring Security + JWT + Redis缓存权限,代码开源在GitHub(Star 120+,虽然不多,但至少证明我能跑通)
- 啃了《Spring Security in Action》:英文原版,边看边骂作者啰嗦,但第9章讲Method Security那段救了我命
- 模拟面试:找朋友扮演面试官,专问Security细节。比如:“FilterChain执行顺序怎么排?UsernamePasswordAuthenticationFilter在哪个位置?”
上个月拿到offer,月薪25k,涨了3k。谈薪时我说:“我不仅会写CRUD,还能守住安全底线。” HR笑了:“现在能配明白Security的人,确实不多。”
最后说点人话
技术人总爱追新:Service Mesh、Dapr、WASM……但别忘了,系统的地基永远是身份认证和权限控制。你用再炫的框架,登录页被爆破,数据全丢,老板照样让你卷铺盖。
Spring Security难吗?难。文档反人类,配置像迷宫。但它值得你花时间。因为它不只是一个框架,而是一种安全思维——知道什么该放行,什么必须拦住,什么需要二次确认。
就像我和女朋友合租,门禁卡她一把,我一把;但她支付宝密码?打死不给。(开玩笑,其实是她不给我看)
给正在挣扎的你
如果你也刚被裁,或者在面试中被Security问题问懵,别慌。我经历过:
- 凌晨三点改配置,结果忘了关CSRF,本地能跑线上500
- 把
antMatchers写成requestMatchers,Spring Boot 3升级踩坑 - 被问“Security底层原理”时大脑空白,只能背八股文
但这些都不丢人。真正的工程师,是在烂泥里也能搭出安全围栏的人。
未来我会继续学Go,不是为了抛弃Java,而是理解不同语言的安全模型。也许明年,我会写《Go中的Casbin实战》,但今天,我依然相信:掌握Spring Security,是你作为Java后端不可妥协的基本功。
共勉。
(写完这篇,女朋友喊我吃宵夜。她说:“你再不关电脑,我就拔电源了。” 得,安全系统再强,也防不住枕边人啊。)

评论 0