spring集成jwt、权限从jwt拿还是从网关拿好

文章目录

      • 引入依赖
        • 0.12(较新)
        • 0.7(过时)
    • boot项目中应用
        • 配置文件中添加
        • 拦截器配置
        • jwt拦截器
        • LoginController
    • 权限从jwt直接拿还是从网关拿好?
        • 单应用为什么难做jwt?
      • 经过网关校验jwt,为什么直接在header中添加jwt不生效?
    • 问题
        • jwt是明文吗?那么还安全吗?

引入依赖

0.12(较新)
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.12.5</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.12.5</version><scope>runtime</scope></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><!-- 用于 JSON 序列化 --><version>0.12.5</version><scope>runtime</scope></dependency>
0.7(过时)

pom.xml添加:

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.7.0</version></dependency><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.2.0</version></dependency>

boot项目中应用

配置文件中添加
jwt:secret:MySuperSecretKeyForJWTTokenGeneration2026VeryLongString# 至少32个字符expiration:86400000# 24小时(毫秒)
拦截器配置
@ConfigurationpublicclassWebMvcConfigimplementsWebMvcConfigurer{@AutowiredprivateJwtInterceptorjwtInterceptor;@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(jwtInterceptor).addPathPatterns("/**").excludePathPatterns("/login/login");}}
jwt拦截器
@ComponentpublicclassJwtInterceptorimplementsHandlerInterceptor{@AutowiredprivateJwtUtiljwtUtil;@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler){Stringtoken=request.getHeader("Authorization");if(token==null||!token.startsWith("Bearer ")){thrownewRuntimeException("未登录");}// 截取 "Bearer " 后面的真实 Tokentoken=token.substring(7);if(!jwtUtil.validateToken(token)){thrownewRuntimeException("Token 已过期或无效");}// 解析并获取用户信息,存入 request 供后续 Controller 使用LonguserId=jwtUtil.getUserId(token);request.setAttribute("userId",userId);returntrue;}}
LoginController
@RestController@Slf4j@RequestMapping("/login")publicclassLoginController{@AutowiredprivateJwtUtiljwtUtil;@RequestMapping("/login")publicStringlogin(Stringusername){// 1. 查库校验用户名密码(省略具体查询逻辑)// 2. 生成 JWT TokenreturnjwtUtil.generateToken(111l,username,"admin");}@GetMapping("/profile")publicJsonResultgetProfile(HttpServletRequestrequest){LonguserId=(Long)request.getAttribute("userId");log.info("userId={}",userId);// 根据 userId 查询业务数据...returnJsonResult.ok(userId);}}

用法:
1、postman先调用login接口 # 拿到jwt
2、post调用profile接口,header里添加Authorization=Bearer jwt值,能够反向拿到userId即可。

权限从jwt直接拿还是从网关拿好?

公司用的是网关拿jwt,然后提取信息放到header中,

对比维度从JWT直接拿(胖JWT模式)从网关拿(瘦JWT+网关鉴权模式)
核心机制JWT的Payload中直接携带用户的角色或权限列表,下游微服务自行解析并校验JWT保持精简(仅含核心标识),API网关负责验签,并将解析出的用户信息放入Header透传给下游
性能与扩展纯本地计算,性能极高;服务间无需通信验证,水平扩展零成本。网关需承担签名验证和IO开销,高并发下易成性能瓶颈;网关宕机存在单点故障风险。
开发与维护各微服务需独立引入并维护鉴权逻辑(如SpringSecurity),重复代码多。下游服务只需读取Header明文,职责分离,代码简洁,维护成本低。
权限实时性无法实时撤销,权限变更或封号需等JWT自然过期才失效。支持动态实时权限,网关可结合Redis黑名单等实现权限秒级生效和强制登出
网络与体积权限多时Token体积膨胀,浪费带宽,易超出HTTPHeader限制导致请求失败。Token保持轻量,避免了携带庞大权限列表,减少网络开销。
安全与隐私Payload仅Base64编码,完整的用户权限画像存在被解码泄露的风险。敏感权限数据无需暴露在公网传输的Token中,相对更安全。
单应用为什么难做jwt?

其实并不是难做,而是分布式不好做。

jwt本身无状态,但是可以jwt+外挂状态,这样网关只用维护一套机制
如果是微服务,那会有分布式噩梦,例如有10个微服务,就要维护10套redis,还要保持同步,这成本就有点高

经过网关校验jwt,为什么直接在header中添加jwt不生效?

一开始也懵了,后来才发现,网关地址和直接项目地址不一样。

网关的作用:拦截并验签,解析jwt并将用户信息传给下游。

https://www.ttt.com # 非网关地址,之前在这里面加的header,没有经过网关,当然也不会解析jwthttps://www.ttt.com/gateway # 网关地址,把请求地址换成这个,jwt就生效了。

问题

jwt是明文吗?那么还安全吗?

是明文,谁拿到后都可以解出信息。

那么还安全吗?
安全,明文虽然可以看到,但是如果密钥验证不通过,可以拦下来,通过权还是牢牢的掌控在自己手里。