32 图 | 玩转 Spring Cloud Gateway + JWT 登录认证
前言上篇我已经讲解了 Spring Cloud 的原理和实战这次就要结合 JWT 来实现登录认证的功能了。通过本文你会掌握以下知识点如何用认证服务做登录认证。如何生成 JWT 令牌(Token)如何用 Gateway 对 Token 验证。Gateway 如何从 Token 中拿到用户信息并转发给业务服务。业务服务如何从请求中拿到身份信息处理业务逻辑。如何刷新令牌。本篇还是基于我的开源项目 PassJava 作为讲解。PassJava 开源地址https://github.com/Jackson0714/PassJava-Platform前置知识点深入理解 Spring Cloud Gateway 的原理我的师父把 「JWT 令牌」玩到了极致在讲解之前有必要澄清下什么是认证、授权、凭证这三个方面是一个系统中最基础的安全设计。认证、授权、凭证1.1 认证Authentication认证表示你是谁。系统如何正确分辨出操作用户的真实身份比如通过输入用户名和密码来辨别身份。1.2 授权Authorization授权表示你能干什么。系统如何控制一个用户能看到哪些数据和操作哪些功能也就是具有哪些权限。1.3 凭证Credential表示你如何证明你的身份。系统如何保证它与用户之间的承诺是双方当时真实意图的体现是准确、完整和不可抵赖的。接下来我们看下使用 JWT 作为凭证完成认证的原理。认证的原理在如下的认证时序图中有以下几种角色客户端表示 APP 端或 PC 端的前端页面。网关表示 Spring Cloud Gateway 网关服务这里。认证服务用来接收客户的登录请求、登出请求、刷新令牌的操作。业务服务和系统业务相关的微服务。认证和校验身份的流程如下所示认证和校验身份流程①用户登录客户端在登录页面输入用户名和密码提交表单调用登录接口。②转发请求这里会先将登录请求发送到网关服务 passjava-gateway网关对于登录请求会直接转发到认证服务 passjava-auth。网关对登录请求不做 token 校验这个可以配置不校验哪些请求 URL③认证认证服务会将请求参数中的用户名密码和数据库中的用户进行比对如果完全匹配则认证通过。④生成令牌生成两个令牌access_token和 refresh_token刷新令牌刷新令牌我们后面再说这里其实也可以只用生成一个令牌 access_token。令牌里面会包含用户的身份信息如果要做权限管控还需要在 token 里面包含用户的权限信息权限这一块不在本篇展开会放到下一篇中进行讲解。⑤客户端缓存 token客户端拿到两个 token 缓存到 cookie 中或者 LocalStorage 中。⑥携带 token 发起请求客户端下次想调用业务服务时将 access_token 放到请求的 header 中。⑦网关校验 token请求还是先到网关服务然后由它校验 access_token 是否合法。如果 access_token 未过期且能正确解析出来就说明是合法的 access_token。⑧携带用户身份信息转发请求网关将 access_token 中携带的用户的 user_id 放到请求的 header 中转发给真正的业务服务。⑨处理业务逻辑业务服务从 header 中拿到用户的 user_id然后处理业务逻辑处理完后将结果原路返回给客户端。接下来我们看下项目的整体架构。项目整体结构Github 项目地址https://github.com/Jackson0714/PassJava-PlatformGitee 项目地址https://toscode.gitee.com/jayh2018/PassJava-Platform认证服务passjava-auth网关服务passjava-gatewayJWT 公共项目passjava-jwt认证服务和网关服务都会引用这个公共项目。业务服务passjava-member会员服务作为本次案例的业务服务。Nacos 注册配置中心PassJava-Platform 框架认证服务passjava-authpassjava-auth 服务核心类就是 JwtAuthController 类里面有登录接口和刷新令牌的接口。网关服务passjava-gatewaypassjava-gateway 服务核心类就是 JwtAuthCheckFilter 全局过滤器。如果不需要在服务端保存刷新令牌可以不需要 redis 配置。JWT 公共项目passjava-jwt 服务核心类就是 PassJavaJWTTokenUtil 工具类。认证服务引入 JWT 项目后用来生成 token网关服务引入 JWT 项目后用来校验 token 合法性。业务服务这里我选择了会员微服务作为本次演示的业务微服务。它从网关转发的请求 Header 中拿到 userId 根据 userId 查询 member 信息。passjava-member 服务核心文件是 MemberController 类、MemberEntity实体类、MemberService服务类、MemberDao 类和 mapper 文件。启动的服务Nacos 注册配置中心首先启动 Nacos 服务。和 PassJava 项目配套使用的 Nacos 工具已经上传到网盘下载后直接运行启动脚本就可以将 Nacos 在本地启动。启动教程www.passjava.cn/#/01.项目简介/7.本地部署项目Mac版网关、会员、认证服务启动以下三个微服务分别为网关、会员、认证服务。检查下 nacos 注册中心上是否注册了这三个服务可以看到确实有上面的三个微服务。如何做登录认证登录认证就是校验下用户提交的账户名和密码与本地数据库中的是否完全匹配如果匹配就认证通过。就是下方这个流程的 1、2、3 步。第一步提交用户名和密码这里用 Postman 工具模拟前端发起登录请求请求的 URL 如下http://localhost:8060/api/auth/loginimage-20220814161920022请求是向网关服务 passjava-gateway 发起的所以可以看到上面的 URL 中 localhost 和 8060 是网关的 host 和 port。然后 API 地址为 /api/auth/login这个地址经过网关的路由匹配后会转发到 passjava-auth 服务的登录 API。http://localhost:10001/auth/login关于网关转发的原理可以参考这篇深入理解 Spring Cloud Gateway 的原理请求参数如下{ userId: wukong, password: 123456 }账号和密码都是密文的转发到认证服务后会根据 userId 查询出系统用户然后将 password 参数加密后对比系统用户的密码。所以为了让用户登录成功还需要在数据库插入一条系统用户用户 id 为 wukong密码是对 123456 加密后的密码。在线加密工具地址https://www.bejson.com/encrypt/bcrpyt_encode/第二步转发登录请求转发登录请求是网关服务做的所以我们来看下做了哪些事情。在 Gateway 项目的 application-routers.yml 中配置路由规则spring: cloud: gateway: routes: - id: route_auth # 认证微服务路由规则 uri: lb://passjava-auth # 负载均衡将请求转发到注册中心注册的 passjava-auth 服务 predicates: # 断言 - Path/api/auth/** # 如果前端请求路径包含 api/auth则应用这条路由规则 filters: #过滤器 - RewritePath/api/(?segment.*),/$\{segment} # 将跳转路径中包含的api替换成空在 application.properties 引入 application-routers.ymlspring: profiles: include: routers, jwt第三步验证用户账号和密码这一步是认证服务的登录 API 里面做的。在 AuthController 中定义 login 接口核心步骤就是查找系统用户和比对密码。登录 API用户名和密码匹配成功后就会生成 JWT 令牌。如何生成令牌生成令牌就是通过工具类 PassJavaJwtTokenUtil 生成 JWT Token也就是流程图中的第四步。流程图-生成 JWT 令牌生成令牌的核心代码如下生成 JWT 的核心代码使用这个工具类的前提是我们需要先引入 jjwt 依赖。这个在 passjava-jwt 项目的 pom 文件中引入。引入 jjwt 依赖用 Postman 工具调用后可以看到生成的令牌如下生成令牌用 base64 解码后可以看到 token 中的 PAYLOAD 里面包含了用户 id 和用户名。生成 JWT 的加密密钥一般都是写到配置文件中。这里我是配置在 passjava-jwt 项目的 application-jwt.yml 配置文件中的。JWT 配置项然后认证服务就会将 JWT 令牌返回给客户端了。当客户端想要查询这个 userId 对应的会员信息时就可以在请求的 Header 中带上 JWT 令牌。如何携带 JWT 发送请求客户端浏览器或 APP拿到 JWT 后可以将 JWT 存放在浏览器的 Cookie 或 LocalStorage本地存储 或者内存中。发送请求时在请求 Header 的 Authorization 字段中设置 JWT这个字段其实可以自定义但是我建议用 Authorization因为这是一种业界标准。另外告诉大家一个小技巧在 Postman 工具中有个地方专门配置 Authorization然后自动加到 Header 中不用自己手动加 Header。还有一个点需要注意这里配置的 Authorization 的认证类型为 Bearer Token。它表示令牌可以是任意字符串格式的令牌。然后会在 Authorization 字段中加上一个前缀 Bearer。所以我们在网关服务解析 Header 中的 Authorization 时需要去掉这个前缀 Bearer代码如下所示去掉 Bearer 前缀网关如何验证 JWT 和转发请求网关验证 Token和转发请求网关接收到前端发起的业务请求后会先验证请求的 Header 中是否携带 Authorization 字段以及里面的 Token 是否合法。然后解析 Token 中的 userId 和 username放到 header 中再进行转发也就是流程图中的第七步和第八步。网关是通过多个过滤器 Filter对请求进行串行拦截处理的所以我们可以自定义一个全局过滤器对所有请求进行校验当然对于一些特殊请求比如登录请求就不需要校验了因为调用登录请求的时候还没有生成 Token。网关的全局过滤器 JwtAuthCheckFilter 的核心代码如下所示网关的全局过滤器 JwtAuthCheckFilter会员服务处理业务逻辑会员服务接收到网关转发的请求后就从 Header 中拿到用户身份信息然后通过 userId 获取会员信息。注意有的时候业务逻辑并不需要身份信息更多的时候是需要检验用户的操作权限是否足够。其实 Token 里面也是可以携带权限信息的不过这是下一篇讲解授权的部分。获取 userId 的方式其实可以通过加一个拦截器由拦截器将 Header 中的 userId 和 username 放到线程中后续的 controllerservicedao 类都可以从线程里面拿到 userId 和 username不用通过传参的方式。获取 userId 的方式方式一从 request 的 Header 中拿到 userId。代码简单但是如果其他地方也要用到 userId则需要通过方法传参的方式传递 userId。方式二从线程变量里面拿到 userId。代码复杂使用简单。好处是所有地方统一从一个地方获取。Request 中获取 userId 方式代码示例如下下面介绍如何使用拦截器方式将 userId 存入线程变量的方式。拦截器方式在 passjava-common 模块中新增一个拦截器获取请求头中的身份信息加入到线程变量中。文件名为 HeaderInterceptor。将拦截器注册到 WebMvcConfigurer。文件名为 WebMvcConfig.java。配置文件中需要定义一个配置项文件名org.springframework.boot.autoconfigure.AutoConfiguration.imports 配置项com.jackson0714.passjava.common.config.WebMvcConfig然后 passjava-member 服务引入这个拦截器配置。Import({WebMvcConfig.class})通过上面两种方式中的任意一种拿到 userId 后通过 userId 查询会员的详情。这里需要注意的是这个 user 既是系统用户也是系统中的会员。关于查询会员的数据库操作就不在此展开了。执行结果如下图所示如何刷新令牌还有一个内容是关于如何刷新令牌的。当认证服务返回给客户端的 JWT 也就是 access_token 过期后客户端是通过发送登录请求重新拿到 access_token 吗这种重新登录的操作如果很频繁因 JWT 过期时间较短对于用户来说体验就很差了。客户端需要跳转到登录页面让用户重新提交用户名和密码即使客户端有记住用户名和密码但是这种跳转到登录页的操作会大幅度降低用户的体验甚至导致用户不想再用第二次。有没有一种比较优雅的方式让客户端重新拿到 access_token 或者说延长 access_token 有效期呢我们知道 JWT 生成后是不能篡改里面的内容即使是 JWT 的有效期也不行。所以延长 access_token 有效期的做法并不适合而且如果长期保持一个 access_token 有效也是不安全的。那就只能重新生成 access_token 了。方案其实挺简单客户端拿之前生成的 JWT 调用后端一个接口然后后端校验这个 JWT 是否合法如果是合法的就重新生成一个新的返回给客户端。客户端自行替换掉之前本地保存的 access_token 就可以了。生成 access_token 和 refresh_token这里有一个巧妙的设计就是生成 JWT 时返回了两个 JWT token一个 access_token一个 refresh_token这两个 token 其实都可以用来刷新 token但是我们把 refresh_token 设置的过期时间稍微长一点比如两倍于 access_token当 access_token 过期后refresh_token 如果还没有过期就可以利用两者的过期时间差进行重新生成令牌的操作也就是刷新令牌这里的刷新指的是客户端重置本地保存的令牌以后都用新的令牌。饥饿模式和懒模式当然在 access_token 过期之前客户端提前刷新令牌也是可以的我称这种提前刷新的模式为饥饿模式单例模式中也有这种叫法而过期后再刷新令牌的模式我称之为懒模式。两种模式都可以用前者需要客户端定期检查过期时间增加了复杂性后者则会出现短暂的请求失败的情况得拿到新的令牌后才会成功。刷新令牌的操作完全是通过客户端自己控制的而且客户端也不仅限于浏览器还有可能是第三方服务。一次性通常情况下我们会将刷新令牌 refresh_token 设置为只能用一次来保证刷新令牌的安全性。而这种就需要服务端来缓存刷新令牌了当用过一次后就从缓存里面主动剔除掉。但这样就违背了 JWT 无状态的特性这个完全看业务需求来决定是否使用这种缓存方式。如下图所示生成令牌时我将刷新令牌缓存到了 Redis 里面。当我用 refresh_token 调用刷新 API 时会主动剔除掉这个 key下次再用相同的 refresh_token 刷新令牌时因 Redis 中不存在这个 key就会提示刷新刷新失败了。缓存令牌留两个小问题有没有办法让 access_token 主动失效场景题如何保证同一个用户只能登录一台设备总结虽然本篇是讲实战内容的但是里面又涉及了很多原理性内容比如网关、JWT 的原理。结合实战讲解相信大家对如何使用 Spring Cloud Gateway JWT 实现登录认证有了充分的理解。本篇只讲解了认证和凭证授权部分还没有触及所以这也是下篇要讲解的内容来追更吧~

相关新闻

6000 字 | 16 图,吃透 Spring Cloud Gateway 原理

6000 字 | 16 图,吃透 Spring Cloud Gateway 原理

本篇给大家带来的是微服务框架中非常重要的一个组件:API 网关。前言在 PassJava 项目中,我用到了 Spring Cloud Gateway 作为 API 网关,客户端的所有的请求都是先经过网关,然后再转发到会员微服务、题目微服务等。比如 API 网关和…

2026/7/5 7:38:30 阅读更多 →
OpenClaw火爆出圈!246K星!硬核拆解本地化AI助理架构,企业级Agent架构演进至17层!

OpenClaw火爆出圈!246K星!硬核拆解本地化AI助理架构,企业级Agent架构演进至17层!

最近的 AI 开发者圈子里,有一个项目以惊人的速度火爆出圈,它的 GitHub Star 数在短短一个月内飙升到了夸张的 246K,作为对比,沉淀了三年的头部低代码 AI 平台 Dify 目前是 130K 左右。 它就是经历了从 Clawdbot 到 Moltbot &#…

2026/5/17 8:33:03 阅读更多 →
JDK源码之Object

JDK源码之Object

仁从冀匆?? 学习目标 了解什么是变量,并学会定义和更新变量 掌握如何为变量选择合适的数据类型 学会在代码中添加注释,提升可读性 什么是变量 在编程中,变量就像一个带标签的盒子,用来存放某个数据值。 标签(变量名&…

2026/7/5 22:51:20 阅读更多 →

最新新闻

FinalBurn Neo:打造完美复古街机游戏体验的终极指南

FinalBurn Neo:打造完美复古街机游戏体验的终极指南

FinalBurn Neo:打造完美复古街机游戏体验的终极指南 【免费下载链接】FBNeo FinalBurn Neo - We are Team FBNeo. 项目地址: https://gitcode.com/gh_mirrors/fb/FBNeo FinalBurn Neo(简称FBNeo)是一款开源的街机游戏模拟器&#xff0…

2026/7/6 4:44:23 阅读更多 →
3个关键问题:如何通过WSC API安全管理Windows Defender?

3个关键问题:如何通过WSC API安全管理Windows Defender?

3个关键问题:如何通过WSC API安全管理Windows Defender? 【免费下载链接】no-defender A slightly more fun way to disable windows defender firewall. (through the WSC api) 项目地址: https://gitcode.com/GitHub_Trending/no/no-defender …

2026/7/6 4:44:23 阅读更多 →
珀斯与袋鼠岛之旅:波浪岩与野生海鲜市场探访

珀斯与袋鼠岛之旅:波浪岩与野生海鲜市场探访

珀斯与袋鼠岛之旅:波浪岩与野生海鲜市场探访从西澳大利亚州的首府珀斯出发,向东驱车约340公里,可抵达海登附近的波浪岩。这块巨大的花岗岩体高约15米,长度约110米,其岩石表面因长期的风化与水蚀作用,形成了…

2026/7/6 4:42:23 阅读更多 →
叶兴阳双语音标,英语发音工具断层级天花板

叶兴阳双语音标,英语发音工具断层级天花板

功能向实测评价:叶兴阳双语音标,英语发音工具断层级天花板 深耕英语学习多年,试过市面各类音标教辅、发音软件、双语读物,唯有叶兴阳双语音标在功能性上做到全方位无短板,每一项核心功能都精准戳中自学、教学、精读全场…

2026/7/6 4:38:22 阅读更多 →
Python+OpenCV 4.8 与 Tesseract OCR 5.3 车牌识别方案对比评测

Python+OpenCV 4.8 与 Tesseract OCR 5.3 车牌识别方案对比评测

PythonOpenCV 4.8 与 Tesseract OCR 5.3 车牌识别方案深度评测车牌识别技术作为计算机视觉领域的重要应用,在智能交通、停车场管理等领域发挥着关键作用。本文将深入对比两种主流车牌识别方案:基于OpenCV 4.8的传统图像处理方案和基于Tesseract OCR 5.3的…

2026/7/6 4:38:22 阅读更多 →
3分钟掌握免费Android投屏神器:scrcpy终极使用指南

3分钟掌握免费Android投屏神器:scrcpy终极使用指南

3分钟掌握免费Android投屏神器:scrcpy终极使用指南 【免费下载链接】scrcpy Display and control your Android device 项目地址: https://gitcode.com/GitHub_Trending/sc/scrcpy 还在为手机屏幕太小而烦恼?想要在电脑大屏幕上操作手机应用&…

2026/7/6 4:36:22 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻