微服务认证与授权:09 — banking-api-service(资源服务器)
09 — banking-api-service资源服务器 GitHub: https://github.com/geekchow/micro-service-auth这个 Spring Boot 服务拥有受保护的银行数据并在每个请求上作为纵深防御层再次检查安全性。该服务做什么banking-api-service暴露两个端点GET /api/accounts/{accountId}GET /api/accounts/{accountId}/transactions它返回简单的内存银行数据。本文关注的是它的安全行为而非数据存储。安全职责认证 bearer 令牌校验 JWT 的签名、签发者与受众依据 JWT 声明对请求的账户进行授权为什么该服务仍要做安全检查Kong是边缘的 PEPOPA是判定 allow/deny 的 PDP。但banking-api-service仍然是一个独立的信任边界。PEP/PDP/资源服务器的定义见 01 — 概念。该服务再次检查的理由服务可能在网络内部被直接调用绕过Kong网关配置错误可能让没有有效令牌的请求通过未来的路由可能绕过部分边缘逻辑纵深防御是良好的安全实践 —— 每一层都应保护自身因此该服务重复关键检查签名、签发者、受众以及账户级授权。请求流程概览Incoming HTTP requestSpring Security filter chainJwtDecoderSignature · issuer · audience validationAuthenticated Jwt principalAccountAccessGuardAccountController or TransactionControllerAccountRepository / TransactionRepositoryJSON responseSecurityConfig装配SecurityConfig标注了Configuration。Spring Boot 在启动时发现它并从中创建两个 beanSecurityFilterChainJwtDecoderSecurityFilterChainBeanSecurityFilterChainsecurityFilterChain(HttpSecurityhttp)throwsException{returnhttp.csrf(csrf-csrf.disable()).authorizeHttpRequests(authorize-authorize.requestMatchers(/actuator/health).permitAll().anyRequest().authenticated()).oauth2ResourceServer(oauth2-oauth2.jwt(Customizer.withDefaults())).build();}每一行的含义禁用 CSRF —— 这是一个无状态 API不是浏览器表单应用/actuator/health公开 —— 容器健康检查需要其余一切都要求认证.oauth2ResourceServer(...jwt(...))安装 JWT 认证过滤器这些过滤器提取Authorization: Bearer令牌并在控制器被调用之前请JwtDecoder校验它。JwtDecoderBeanJwtDecoderjwtDecoder(Value(${spring.security.oauth2.resourceserver.jwt.jwk-set-uri})StringjwkSetUri,Value(${banking-api.security.issuer-uri})StringissuerUri,Value(${banking-api.security.audience})Stringaudience){NimbusJwtDecoderjwtDecoderNimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();jwtDecoder.setJwtValidator(jwtValidator(issuerUri,audience));returnjwtDecoder;}NimbusJwtDecoder.withJwkSetUri(...)从Keycloak的 JWKS 端点获取公钥并用它们验证令牌签名。随后一个自定义的jwtValidator检查签发者与受众。该服务使用 JWKS公钥验证而非令牌内省 —— 无状态、每个请求都不需要往返Keycloak。关于这一选择背后的理由见 11 — JWT 签名、校验与内省。关于 JWKS 机制见 12 — JWKS 深入解析。配置application.yml中的键键用途spring.security.oauth2.resourceserver.jwt.jwk-set-uri获取Keycloak公钥的 URLbanking-api.security.issuer-uri受信任的签发者必须与 JWT 的iss声明匹配banking-api.security.audience必需的受众值必须出现在 JWT 的aud声明中环境变量来自docker-compose.yml变量Docker Compose 中的值BANKING_API_JWK_SET_URIhttp://keycloak:8080/realms/banking-poc/protocol/openid-connect/certsBANKING_API_ISSUER_URIhttp://keycloak:8080/realms/banking-pocBANKING_API_AUDIENCEmobile-banking-appJWT 校验SecurityConfig中的jwtValidator方法组合了两个校验器签名NimbusJwtDecoder使用从Keycloak的 JWKS 端点获取的密钥验证令牌签名。被篡改的令牌会立即失败。签发者JwtValidators.createDefaultWithIssuer(issuerUri)检查iss声明是否与配置的Keycloakrealm 匹配。来自不同签发者的令牌会被拒绝。受众一个JwtClaimValidator检查aud声明是否包含mobile-banking-app。不针对本应用的令牌会被拒绝。若任一检查失败Spring Security 返回401 Unauthorized控制器永不会被调用。该服务读取哪些声明AccountAccessGuard从已校验的Jwt中读取三个声明声明读取方式realm_access.rolesjwt.getClaim(realm_access)转为Map再get(roles)customer_idjwt.getClaimAsString(customer_id)account_idsjwt.getClaimAsStringList(account_ids)整个系统的完整声明目录见 14 — 请求与响应细节。Spring Security 在运行时如何装配SecurityConfig启动时Spring 发现SecurityConfigConfiguration创建SecurityFilterChainbean —— 安装 JWT 过滤器链创建JwtDecoderbean —— Spring Security 自动使用它每个请求JWT 过滤器提取 bearer 令牌JwtDecoder校验签名、签发者、受众Spring 把已认证的Jwt存入安全上下文控制器通过AuthenticationPrincipal Jwt jwt接收它控制器调用AccountAccessGuard做授权AccountAccessGuardAccountControllerSecurityContextJwtDecoderSpring Security filter chainIncoming requestAccountAccessGuardAccountControllerSecurityContextJwtDecoderSpring Security filter chainIncoming requestalt[invalid token][valid token]HTTP GET Authorization: Bearer tokenvalidate JWTvalid or invalid401 Unauthorizedstore authenticated Jwt principalinject AuthenticationPrincipal JwtcheckCanAccessAccountId(accountId, jwt)allow or 403checkCanAccess(account, jwt)allow or 403200 JSON or 404AccountAccessGuard文件services/banking-api-service/src/main/java/com/banking/poc/bankingapi/account/AccountAccessGuard.java该守卫有两个公开方法checkCanAccessAccountId(String accountId, Jwt jwt)—— 在仓库查找之前调用checkCanAccess(AccountDto account, Jwt jwt)—— 在账户加载之后调用为什么有两次检查第一次检查 —— 账户 ID 预检checkCanAccessAccountId尽早拒绝明显被禁止的账户 ID减少信息泄露 —— 对于将被拒绝的请求服务不触碰仓库避免为调用方明显无法访问的请求加载数据第二次检查 —— 对象级检查checkCanAccess确认已加载账户的customerId确实与 JWT 的customer_id匹配为「账户/客户关系与仅凭 ID 所暗示的不一致」的情形增加一层保险授权规则规则 1 —— 无 JWT →401若Jwt对象为null守卫抛出401 Unauthorized。规则 2 ——ops-admin可访问任意账户若realm_access.roles包含ops-admin两次检查都无条件通过。规则 3 ——customer必须匹配声明上下文对checkCanAccessAccountId以下全部必须为真realm_access.roles包含customercustomer_id声明非 null 且非空白account_ids声明包含请求的accountId对checkCanAccess还需额外满足account.customerId()等于 JWT 的customer_idaccount.accountId()在 JWT 的account_ids列表中规则 4 —— 否则403AccountController文件services/banking-api-service/src/main/java/com/banking/poc/bankingapi/account/AccountController.java端点GET /api/accounts/{accountId}GetMapping(/{accountId})publicAccountDtogetAccount(PathVariableStringaccountId,AuthenticationPrincipalJwtjwt){accountAccessGuard.checkCanAccessAccountId(accountId,jwt);AccountDtoaccountaccountRepository.findById(accountId).orElseThrow(()-newResponseStatusException(HttpStatus.NOT_FOUND));accountAccessGuard.checkCanAccess(account,jwt);returnaccount;}流程从路径接收accountId从安全上下文接收已校验的JwtcheckCanAccessAccountId—— 若调用方无法访问该账户 ID尽早拒绝从AccountRepository加载账户 —— 未找到则返回404checkCanAccess—— 确认已加载账户与调用方的声明上下文匹配以 JSON 返回AccountDtoTransactionController文件services/banking-api-service/src/main/java/com/banking/poc/bankingapi/transaction/TransactionController.java端点GET /api/accounts/{accountId}/transactionsGetMapping(/{accountId}/transactions)publicListTransactionDtogetTransactions(PathVariableStringaccountId,AuthenticationPrincipalJwtjwt){accountAccessGuard.checkCanAccessAccountId(accountId,jwt);AccountDtoaccountaccountRepository.findById(accountId).orElseThrow(()-newResponseStatusException(HttpStatus.NOT_FOUND));accountAccessGuard.checkCanAccess(account,jwt);returntransactionRepository.findByAccountId(accountId);}流程与AccountController相同。两次守卫检查都通过后控制器从TransactionRepository加载交易列表并返回。类之间的关系SecurityConfigJwtDecoderSecurityFilterChainAccountControllerTransactionControllerAccountAccessGuardAccountRepositoryTransactionRepository互操作与KeycloakKeycloak签名 JWT、设置签发者并嵌入customer_id、account_ids与角色声明。该服务用Keycloak的 JWKS 端点校验签名并且不信任来自未签名或错误签发令牌的任何声明。与KongKong是把请求转发到banking-api-service的 PEP。然而该服务并不无条件信任Kong—— 它独立校验 JWT。这意味着对该服务的直接调用绕过Kong仍会得到同样的安全执行。与OPAOPA是Kong在边缘咨询的 PDP。banking-api-service不直接调用OPA。取而代之它从受信任的 JWT 声明出发再次执行同样的业务访问规则账户归属、角色。边缘与服务会收敛到同一答案因为二者读取的是同一组声明。与identity-bootstrap-serviceidentity-bootstrap-service创建带有角色、customer_id与account_ids的Keycloak用户。这些值会嵌入到banking-api-service后续接收并校验的每个 JWT 中。实际示例示例 1 ——alice访问她自己的账户alice的 JWTrealm_access.roles[customer]customer_idC-1001account_ids[A-1001]请求GET /api/accounts/A-1001结果JWT 校验通过签名、签发者、受众checkCanAccessAccountId通过A-1001在account_ids中加载账户checkCanAccess通过customerId匹配200 OK及账户 JSON示例 2 ——alice请求一个她不拥有的账户JWT 同上。请求GET /api/accounts/A-2001结果JWT 校验通过checkCanAccessAccountId失败A-2001不在account_ids [A-1001]中403 Forbidden—— 控制器永不执行示例 3 ——ops-admin访问任意账户ops-admin的 JWTrealm_access.roles[ops-admin]请求GET /api/accounts/A-2001结果JWT 校验通过checkCanAccessAccountId通过角色ops-admin短路加载账户checkCanAccess通过角色ops-admin短路200 OK及账户 JSON示例 4 —— 被篡改的令牌请求携带一个签名无效的 JWT。结果JwtDecoder在签名验证时拒绝该令牌Spring Security 返回401 Unauthorized控制器永不执行思维模型SecurityConfig在启动时装配两个 beanSecurityFilterChain与JwtDecoder每个请求过滤器链提取并校验 bearer 令牌签名 → 签发者 → 受众有效令牌成为一个受信任的Jwtprincipal通过AuthenticationPrincipal注入AccountAccessGuard使用realm_access.roles、customer_id与account_ids执行账户级授权只有在认证与授权检查都通过后控制器才返回数据← Prev: 08 — OPA · Next: 10 — identity-bootstrap-service →

相关新闻

Linux环境变量与数组变量学习小结

Linux环境变量与数组变量学习小结

环境变量是Linux系统中存储系统环境信息的重要机制,它们分为全局环境变量和局部环境变量两种类型。全局环境变量(也称为系统环境变量)对当前Shell及其所有子Shell可见,通常在系统启动时加载,而局部环境变量仅在定义它们…

2026/7/9 6:55:10阅读更多 →
突发!阿里全面禁用Claude Code!2026AI圈重磅变局,背后攻防远比你想象的更残酷

突发!阿里全面禁用Claude Code!2026AI圈重磅变局,背后攻防远比你想象的更残酷

2026年AI圈最大变局,正式落地!近日,阿里内部正式官宣:全面禁用Claude Code全系产品,将其列入高风险软件黑名单,全员禁止在办公环境、开发设备、内网工程中使用,7月10日起全集团强制执行。消息一…

2026/7/9 6:55:10阅读更多 →
龙虾3.13部署避坑指南:环境、配置与命令失效的深层根因

龙虾3.13部署避坑指南:环境、配置与命令失效的深层根因

1. “一键部署”背后的三重幻觉:为什么龙虾3.13的安装脚本从不告诉你真实成本“OpenClaw 龙虾 3.13 一键部署成功!”——这句话在技术社区里出现频率极高,截图里终端窗口绿字滚动、服务端口亮起、Web界面弹出,看起来毫无破绽。我去…

2026/7/9 6:55:10阅读更多 →
JetBrains IDE试用期重置终极指南:如何轻松恢复30天免费使用权

JetBrains IDE试用期重置终极指南:如何轻松恢复30天免费使用权

JetBrains IDE试用期重置终极指南:如何轻松恢复30天免费使用权 【免费下载链接】ide-eval-resetter 项目地址: https://gitcode.com/gh_mirrors/id/ide-eval-resetter 还在为IntelliJ IDEA、PyCharm、WebStorm等JetBrains IDE试用期到期而烦恼吗&#xff1f…

2026/7/9 8:10:18阅读更多 →
MP2315GJ-Z 3A同步降压芯片:从4.5V到24V宽压输入的5个PCB布局关键点

MP2315GJ-Z 3A同步降压芯片:从4.5V到24V宽压输入的5个PCB布局关键点

MP2315GJ-Z 3A同步降压芯片:从4.5V到24V宽压输入的5个PCB布局关键点在硬件设计中,电源模块的稳定性往往决定了整个系统的可靠性。MP2315GJ-Z作为一款支持4.5V至24V宽输入范围、输出电流达3A的高频同步降压芯片,其性能潜力很大程度上取决于PCB…

2026/7/9 8:10:18阅读更多 →
餐饮线上下单系统哪个好?点餐、支付和会员复购功能对比

餐饮线上下单系统哪个好?点餐、支付和会员复购功能对比

餐饮线上下单系统哪个好?点餐、支付和会员复购功能对比餐饮线上下单系统哪个好,要看它能不能同时处理顾客体验和门店效率。顾客关心菜单清不清楚、支付顺不顺、取餐时间准不准;门店关心订单提醒是否及时、后厨是否看得懂、优惠券能不能核销、…

2026/7/9 8:10:18阅读更多 →
基于MATLAB图像处理的啤酒瓶口缺陷检测系统设计与实现

基于MATLAB图像处理的啤酒瓶口缺陷检测系统设计与实现

摘要:本文针对啤酒生产线质量检测的实际需求,设计并实现了一套基于机器视觉的啤酒瓶口缺陷检测系统。该系统采用 MATLAB 平台开发,融合了图像预处理、Otsu 自适应阈值分割、形态学运算、投影定位、圆形度分析、环形区域检测及对称性判定等多种…

2026/7/9 8:10:18阅读更多 →
HNCTF PatrolNote

HNCTF PatrolNote

考点:Android APK 逆向 SO 原生层逆向 字符串置换 / AES 密码学 正则分组 数组下标置换逆推 AES-128 一、阶段 1:Java 层定位 Native 本地方法 apk文件,直接搜索native进入jadx的native 可以看见本题核心函数是nativeVerify&#xff0…

2026/7/9 8:10:18阅读更多 →
CubeSandbox:面向 AI Agent 的即时、并发、安全轻量沙箱服务

CubeSandbox:面向 AI Agent 的即时、并发、安全轻量沙箱服务

CubeSandbox:面向 AI Agent 的即时、并发、安全轻量沙箱服务 📌 核心观点 CubeSandbox 是腾讯云开源的高性能沙箱服务,专为 AI Agent 代码执行场景设计。它基于 RustVMM KVM 构建,在安全性(硬件级隔离)与…

2026/7/9 8:05:18阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/9 5:56:19阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/8 7:00:12阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/9 2:47:07阅读更多 →
Three.js 着色器光效教程

Three.js 着色器光效教程

着色器光效 Shader Light ▶ 在线运行案例 案例合集: 三维可视化功能案例(threehub.cn)开源仓库github地址: https://github.com/z2586300277/three-cesium-examples400个案例代码: 网盘链接 你将学到什么 ShaderMaterial 自…

2026/7/9 0:04:37阅读更多 →
如何5分钟掌握CS2智能库存管理:开源工具CASEMOVE终极指南

如何5分钟掌握CS2智能库存管理:开源工具CASEMOVE终极指南

如何5分钟掌握CS2智能库存管理:开源工具CASEMOVE终极指南 【免费下载链接】casemove A dedicated desktop app that enables you to move items in and out of storage units in CS2. 项目地址: https://gitcode.com/gh_mirrors/ca/casemove 还在为CS2存储单…

2026/7/9 0:04:37阅读更多 →
GBase 8a vs MySQL 8.0:ALTER TABLE语法与限制的5点关键差异对比

GBase 8a vs MySQL 8.0:ALTER TABLE语法与限制的5点关键差异对比

GBase 8a与MySQL 8.0:ALTER TABLE语法差异深度解析与实战指南1. 两种数据库的ALTER TABLE能力全景对比在数据库架构设计和运维过程中,表结构变更(DDL操作)是不可避免的需求。GBase 8a作为国产分析型数据库代表,与开源M…

2026/7/9 0:04:37阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/8 6:59:54阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/8 13:42:39阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/8 13:42:39阅读更多 →