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是明文吗?那么还安全吗?
是明文,谁拿到后都可以解出信息。
那么还安全吗?
安全,明文虽然可以看到,但是如果密钥验证不通过,可以拦下来,通过权还是牢牢的掌控在自己手里。