上篇登录跑通拿到了 token。这篇解决token 发出去之后怎么用拦截器统一验签业务代码零感知地拿到当前用户。为什么不用 Spring Security我的场景两种角色USER/DRIVER/ADMIN、几十个接口、无 OAuth 无 SSO。Spring Security 的过滤器链、SecurityContext、UserDetailsService 那一套学习成本远超收益。手写一个 JWT 工具 一个 MVC 拦截器总代码不到 200 行每一行都看得懂、改得动。小项目的安全感来自简单不是来自重量级框架。三件套JwtUtil、AuthContext、拦截器1. JwtUtil手写 HS256JWT 结构是header.payload.signatureHS256 的签名就是HMAC-SHA256(header . payload, secret)。不引第三方库也能写publicstaticStringcreate(LonguserId,Stringrole){Stringheaderbase64({\alg\:\HS256\,\typ\:\JWT\});Stringpayloadbase64({\uid\:userId,\role\:\role\,\exp\:(System.currentTimeMillis()/10007*86400)});StringsignhmacSha256(header.payload,SECRET);returnheader.payload.sign;}解析时先验签再取uid/role过期抛异常。就这么多没有魔法。2. AuthContextThreadLocal 存当前用户publicclassAuthContext{privatestaticfinalThreadLocalLongUIDnewThreadLocal();publicstaticvoidset(Longuid){UID.set(uid);}publicstaticLonguid(){returnUID.get();}publicstaticvoidclear(){UID.remove();}// 关键}3. 拦截器验签 放行名单publicclassAuthInterceptorimplementsHandlerInterceptor{publicbooleanpreHandle(HttpServletRequestreq,HttpServletResponseresp,Objecth){Stringtokenreq.getHeader(Authorization);// Bearer eyJ...LonguidJwtUtil.parseUserId(token.replace(Bearer ,));if(uidnull){resp.setStatus(401);returnfalse;}AuthContext.set(uid);returntrue;}publicvoidafterCompletion(...){AuthContext.clear();}}注册时排除公开接口/api/auth/**、/api/vehicle-types、管理端登录等。之后所有 Controller 写起来非常干净GetMapping(/api/me)publicResultme(){returnResult.ok(userService.info(AuthContext.uid()));// 当前用户直接拿}三个必踩的坑提前避开ThreadLocal 必须 removeTomcat 线程是复用的不清理会串用户——这是隐蔽性最高的线上事故来源。放afterCompletion里最保险放行名单别用通配符放开整个 /api宁可逐个加白名单过期策略从简7 天过期 过期重登。token 自动续期refresh token第一版不需要别给自己加戏本篇成果全站鉴权闭环前端请求头自动带 token → 拦截器验签 → 业务代码AuthContext.uid()直取当前用户。下一篇写整个系统的心脏订单状态机与下单支付。