Spring Security基础:快速搭建安全认证系统 —— 一个35岁老码农的血泪经验

半杯咖啡写代码
2026-02-28 10:28
阅读 2339

上周五晚上十一点,我正瘫在成都温江那套月租3500的老小区沙发上,一边啃着老婆留的冷锅盔,一边改一个烂到家的权限模块。突然微信弹出一条消息,是前同事老张发来的:“哥,你简历上写的‘精通Spring Security’,能帮忙看看我们这个登录死活不跳转的问题吗?”

我苦笑一声,把锅盔放回盘子——哪有什么“精通”,不过是被生活逼出来的熟练工罢了。


一、从“简历写错”到“真香现场”

去年十月,我投了一份成都本地某SaaS公司的Java岗,HR问:“有Spring Security实战经验吗?”
我心一横,打字:“有,主导过RBAC权限系统重构。”
其实呢?我上个项目用的还是Shiro,Security只在B站看过两集视频。但没办法,35岁了,简历不写点“高大上”的,连面试机会都拿不到。月薪15k卡在成都这行里,已经快三年没动过,房贷+娃的奶粉钱压得我喘不过气。

结果面试还真过了。入职第一周,组长丢给我一个任务:“下周上线新后台,用Spring Security搭一套完整的认证授权,支持手机号+验证码+JWT,用户角色要动态加载。”

我当场头皮发麻。回家路上骑共享单车,手都在抖。不是怕技术,是怕露馅。万一搞砸了,35岁被优化,再找工作?简历上“精通”变“造假”,谁还敢要?


二、别信教程,先搭骨架

很多人一上来就看官方文档,或者照着CSDN抄配置。我劝你停一停。Spring Security最坑的地方,不是它难,而是它太灵活,导致你不知道该从哪下手。

我的做法很简单:先搭最小可行骨架,再逐步加功能。

1. 依赖别乱加

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>

注意:别一上来就加spring-security-oauth2,除非你真要做第三方登录。90%的内部系统,用JWT+自定义过滤器就够了。

2. 关闭默认表单登录(重要!)

Spring Security默认会弹出那个丑到爆的登录页。你肯定不想要:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .formLogin().disable() // 关掉!
            .httpBasic().disable()
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated()
            )
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        return http.build();
    }
}

这段代码我改了七遍。第一次忘了关csrf,前端调接口一直403;第二次没设STATELESS,每次请求都带JSESSIONID,和JWT冲突。这些坑,没人告诉你,只能自己踩。


三、JWT不是万能胶水,别乱贴

很多人以为加个JWT就算“安全”了。错!JWT只是令牌载体,真正的安全逻辑在你的过滤器里。

我写了一个JwtAuthenticationFilter,继承OncePerRequestFilter,核心逻辑就三步:

  1. 从Header取Authorization: Bearer <token>
  2. 解析token,校验签名和过期时间
  3. 构造UsernamePasswordAuthenticationToken,塞进SecurityContext

但问题来了:怎么动态加载用户权限?

早期我直接在filter里查数据库,结果QPS一高,DB连接池爆了。后来改成缓存用户角色(用Redis,TTL 30分钟),性能立马稳了。

// 伪代码
String token = getTokenFromHeader(request);
Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
String username = claims.getSubject();
List<SimpleGrantedAuthority> authorities = userRoleCache.get(username); // 从缓存拿
SecurityContextHolder.getContext().setAuthentication(
    new UsernamePasswordAuthenticationToken(username, null, authorities)
);

记住:认证(Authentication)和授权(Authorization)是两回事。 别把权限判断逻辑全塞进filter,留给@PreAuthorizehasRole()去处理。


四、Codeium救了我一命

说真的,要不是用了Codeium(免费的AI编程助手),我可能真得熬通宵。

那天晚上,我在写UserDetailsServiceImpl,实现loadUserByUsername方法。脑子里一团浆糊,想不起怎么把用户实体转成UserDetails。手指一敲,Codeium自动补全:

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    User user = userMapper.selectByUsername(username);
    if (user == null) {
        throw new UsernameNotFoundException("用户不存在");
    }
    return org.springframework.security.core.userdetails.User
        .withUsername(user.getUsername())
        .password(user.getPassword())
        .authorities(user.getRoles().stream()
            .map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName()))
            .toArray(SimpleGrantedAuthority[]::new))
        .build();
}

我愣了三秒,然后默默点了接受。AI不是来取代我们的,是来帮我们填坑的。 尤其当你35岁,脑子不如25岁转得快时,这种工具就是续命丹。


五、技术分享,是我最后的倔强

项目上线后,我主动在公司内部做了次技术分享,主题就是《Spring Security避坑指南》。讲完后,几个年轻同事跑来问:“哥,你咋懂这么多?”

我笑了笑:“不是懂,是摔得够多。”

其实我心里清楚:在成都这种二线城市,技术深度不如一线,但广度必须有。 你不会Security,下个项目可能就轮不到你。而每一次分享,都是在给自己的简历加“真实权重”。

现在我的简历上,“精通Spring Security”后面多了句小字:“基于RBAC模型,支持动态权限+JWT无状态认证,QPS 2000+稳定运行”。虽然HR可能看不懂,但技术面试官一眼就知道——这人真干过。


六、写给和我一样的老码农

35岁还在一线写代码,不是因为热爱,很多时候是没得选。成都工资低,但生活成本也低,房租3500能住三室一厅,老婆做会计,孩子上幼儿园,日子将就过得去。

但将就,不等于躺平。

Spring Security这类框架,学起来枯燥,但它是你对抗年龄焦虑的武器。当别人还在纠结“会不会被AI取代”,你已经用Codeium+扎实的基础,把活干得又快又稳。

技术分享不是为了装逼,是为了让世界知道:我还在线,还能打。


最后一点真心话

如果你也在二线城市,30+,拿着不高不低的工资,担心被淘汰——别慌。深耕一个领域,比如安全认证,把它做到“能讲、能写、能落地”,你就有了护城河。

简历可以包装,但代码骗不了人。Spring Security不难,难的是你愿意花时间去理解它的设计哲学,而不是抄配置。

上周五那个问题,我帮老张解决了。原因很简单:他忘了在HttpSecurity里放行/login接口,导致登录请求被拦截,死循环。

他请我喝了杯瑞幸。我说:“下次别信简历,信实践。”

毕竟,35岁的程序员,剩下的只有真实了。

评论 0

最热最新
暂无评论
半杯咖啡写代码Lv.1
0
影响力
0
文章
0
粉丝