ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Reflex Enterprise MCP 认证完全指南:应用签发令牌、匿名会话与 OAuth 2.1 授权流

Reflex Enterprise MCP 认证完全指南:应用签发令牌、匿名会话与 OAuth 2.1 授权流 Reflex Enterprise MCP 认证完全指南应用签发令牌、匿名会话与 OAuth 2.1 授权流【免费下载链接】reflex️ Web apps in pure Python 项目地址: https://gitcode.com/GitHub_Trending/re/reflexrxe.MCPPlugin让 Reflex 应用通过 Model Context ProtocolMCP对外发布事件处理器与实时状态而这一切的门禁是本文的主题——应用自身签发的 Bearer 令牌。无论是让 LLM Agent 以匿名会话方式驱动应用还是通过 OAuth 2.1 授权流以登录用户身份操作MCP 端点都强制要求令牌且只认应用自己签发的凭证。读完本文你将掌握匿名令牌的获取与约束、OAuth 2.1 授权服务器的完整流程、同意页的安全设计、应用级 scope 的细粒度授权以及面向 MCP 流量的感知来源鉴权检查与限流机制。本文对应仓库文档 docs/enterprise/mcp/authentication.mdreflex-enterprise v0.9.4新增并交叉引用 Auto MCP 总览、生产部署指南、Event Handler API 与 Auth 认证总览 进行纵深展开。认证模型的核心应用签发的会话令牌MCP 端点的每一个请求——以及 Event Handler API 的 REST 端点——都要求一个应用签发的 Bearer 令牌。这套模型有三个关键约束调用方自造的 UUID 永远不会被接受。不能像早期版本那样自行编造一个看起来像会话 ID的字符串充当凭证。任何 MCP 工具都不接受token参数。令牌只能通过Authorization: Bearer access_token请求头发送不存在把令牌塞进工具参数的旁路。底层 Reflex 会话令牌由服务器生成、永不离开服务器。这意味着一个凭证只能寻址它自己专属的会话——无法寻址某个浏览器会话也无法寻址其他 Agent 的会话而客户端能够创建的会话数量受 IP 级限流约束。从设计意图看令牌是某个客户端、它自己的会话这一身份的载体而不是用户身份。因此匿名令牌与 OAuth 令牌天然共存配置了AuthPlugin时这是默认状态两个令牌签发源都会被接线MCP 端点同时接受两者的 Bearer不需要以用户身份行动的 Agent 完全可以跳过登录流程。令牌只有两个来源匿名会话令牌POST /_reflex/auth/token与OAuth 2.1 授权令牌配合AuthPlugin。两者同时可用时由客户端自行选择。匿名会话一条 curl 即可获得最小权限凭证POST /_reflex/auth/token返回一个不透明 Bearer绑定到一个全新的、由服务器生成的匿名会话curl -X POST https://my-app.example/_reflex/auth/token{ access_token: …, token_type: Bearer, expires_in: 3600, session: anonymous }将返回的access_token作为Authorization: Bearer access_token发送到 MCP 端点或 REST API即可。关键语义如下跨调用复用令牌以寻址同一个会话——例如先create_ticket再list_tickets后续调用能看到前一次调用的效果。令牌过期后申请新令牌 全新的空白会话。匿名令牌没有 refresh 机制不存在续期过期即意味着会话结束。默认expires_in为 3600 秒即 配置参考 中的anonymous_session_ttl可配置。匿名会话在启用 AuthPlugin 时的行为边界匿名会话不携带任何用户身份。当应用配置了AuthPlugin时这意味着以下三重限制来源docs/enterprise/mcp/authentication.mdqueue_event会拒绝任何不是authFalse的事件处理器并且返回的是可操作的错误信息而不是静默的跳转 delta受保护 var 会从reflex://state/vars/...读取中被扣留只有authFalse的rxe.mcp.resource方法能够解析AuthUserState.current()返回没有用户。而事件处理器的元数据search_events、reflex://event无论哪种情况都可读。如果没有配置AuthPlugin匿名令牌就是唯一的令牌来源。强制要求登录态 Agent 的两种方式rxe.MCPPlugin(anonymous_sessionsFalse) # MCP 拒绝匿名 Bearer rxe.MCPPlugin(required_scopes[orders:read]) # 匿名令牌不携带任何 scopeanonymous_sessionsFalseMCP 端点拒绝匿名 Bearerrequired_scopes[orders:read]由于匿名令牌不携带 scope设置required_scopes同样会隐式禁用匿名访问。限流为什么每个授权都消耗服务器内存匿名令牌端点按客户端 IP 限流token_rate_limit默认每分钟 10 次因为每一次授权都会在服务端播种一个会话而每个会话都占用内存。这一点在 生产部署指南 中被列为三只每进程限流器之一详见下文限流小节。重要令牌端点与 EventHandlerAPIPlugin 共享令牌端点与 EventHandlerAPIPlugin 共享。先接线的插件决定它的设置TTL、限流且只要任一插件启用该路由就会提供服务。MCPPlugin 上的 anonymous_sessionsFalse 只会让 MCP 端点拒绝匿名 Bearer——但 REST 表面仍会接受共享端点签发的任何令牌所以要在两个插件上都设置 anonymous_sessionsFalse 才能彻底停止签发匿名令牌。换言之Event Handler API 与 Auto MCP 共享同一套令牌端点与认证实现——两个插件暴露的是同一套事件处理器表面认证与限流行为完全一致。OAuth 2.1让 Agent 以登录用户身份行动仅靠匿名会话Agent 无法读取受保护 var也无法调用需要authTrue的事件。要以用户身份操作需要走 OAuth 流程。当配置了AuthPlugin时MCPPlugin会把应用变成符合规范的OAuth 2.1 授权服务器 资源服务器服务于其 MCP 端点并把人类登录联邦到你已经配置的 OIDC 提供商。无需任何额外配置——默认开启config rxe.Config( app_namemy_app, plugins[rxe.AuthPlugin(), rxe.MCPPlugin()], )两种显式覆盖方式MCPPlugin(authFalse)即使旁边配置了AuthPlugin也让端点保持纯匿名MCPPlugin(authTrue)强制要求 OAuth 流程如果未配置AuthPlugin会在接线时快速失败而不是运行期才报错。授权流如何运行一个未认证的 MCP 请求收到401响应携带WWW-Authenticate头指向应用的受保护资源元数据RFC 9728客户端发现授权服务器RFC 8414并动态注册自身RFC 7591客户端在浏览器中打开授权端点。应用重定向到同意页——一个普通的、已认证的 Reflex 页面因此页面守卫会把匿名访问者弹回你标准的/login流程任意已配置的提供商再返回人类批准勾选想要授予的应用 scope应用在服务端对登录态做快照、签发一次性授权码并用自己的、不透明的、绑定资源的 access refresh 令牌PKCE 已验证完成交换令牌携带的正是被授予的那些 scope。OAuth 端点一览端点用途/.well-known/oauth-protected-resource/_reflex/mcpRFC 9728 受保护资源元数据指向 MCP 端点。/.well-known/oauth-authorization-serverRFC 8414 授权服务器元数据。/register-oidc-clientRFC 7591 动态客户端注册按 IP 限流可用enable_dynamic_client_registrationFalse关闭。/authorize授权端点——重定向到同意页。/token令牌端点授权码 refresh 授予refresh 使用时轮换。/revokeRFC 7009 撤销可用enable_token_revocationFalse关闭。这四个端点注册、授权、令牌、撤销被挂在源站根路径上优先于应用自身路由客户端只能通过元数据文档发现它们——所以当路径与应用页面冲突时路径是可配置的rxe.MCPPlugin( registration_path/register-oidc-client, # 默认值 authorization_path/authorize, token_path/token, revocation_path/revoke, )注册端点默认用/register-oidc-client而不是 MCP SDK 自带的裸/register恰恰是因为/register是常见的用户注册页路径否则 OAuth 端点会遮蔽它。每个路径必须互不相同且不能位于 MCP 挂载点之下——这两条约束在接线时就会被检查ConfigError快速失败。上游令牌永不离开服务器MCP 客户端只会持有应用为自己的 MCP 端点签发的令牌上游身份提供商的令牌永不离开服务器。上游刷新在服务端完成如果上游登录过期且无法刷新应用签发的令牌会被撤销工具返回清晰的请重新认证错误客户端据此重跑整个流程。因为每个令牌都绑定到专属的服务端会话完整的强制执行栈对 Agent 流量原样生效逐事件的AuthMiddleware门禁、可调用的auth检查、delta 过滤、多提供商选择、AuthUserState.current()——与浏览器用户的行为完全一致。同意页与 confused-deputy 问题已登录的浏览器通常会跳过身份提供商自己的同意屏因此应用自己的同意页是阻止恶意 MCP 客户端静默冒充用户的关键人工检查点同意页始终同时展示客户端名称与授权码将要发送到的确切 redirect 主机。客户端名称来自动态注册因此是攻击者可控的但 redirect 主机不是。要求显式点击Approve。之前的批准会显示为你已授权过此客户端的提示但绝不会自动提交。同意记录按(user, client, redirect URI)三元组落库作为审计线索。反点击劫持同意路由以X-Frame-Options: DENY和frame-ancestors none响应主要的点击劫持防线且 approve 处理器额外拒绝在检测到的 iframe 内运行。# 前后端分离部署 当 SPA 与后端来自不同源时这些响应头由后端应用覆盖不到单独托管的同意页 HTML。请在前端主机或 CDN 上为同意路由配置同样的反框架头。自定义同意页页面默认位于/agent-consent可用consent_path修改同样不能位于 MCP 挂载点之下。替换组件时遵循与AuthPlugin自定义页面相同的 builder 契约rxe.MCPPlugin(consent_pagemy_app.mcp.consent_page)builder 以plugin关键字参数被调用并返回一个组件。基于MCPConsentState渲染它暴露client_name、redirect_uri、redirect_host、requested_scopes、app_scope_options、app_scope_grants、previously_authorized、error_message与ready以及approve、deny、set_app_scope_grant处理器import reflex as rx from reflex_enterprise.plugins.mcp_auth.consent_state import MCPConsentState def consent_page(**context) - rx.Component: return rx.vstack( rx.heading(fAuthorize {MCPConsentState.client_name}), rx.text( fThe authorization code will be sent to {MCPConsentState.redirect_host} ), rx.hstack( rx.button( Approve, on_clickMCPConsentState.approve, disabled~MCPConsentState.ready, ), rx.button(Deny, on_clickMCPConsentState.deny, variantsoft), ), )应用级 scope细粒度授权批准一个客户端不应把用户的全部权限都交给 Agent。声明应用级 scope 让授权变得粒度化rxe.MCPPlugin( app_scopes{ orders:read: Read your order history, orders:write: Place and modify orders, }, )每个应用 scope 在同意屏上表现为可单独授予的复选框——客户端请求过的 scope 默认勾选其余默认不勾选。签发的 access/refresh 令牌携带的正是人类实际授予的 scope且跨所有已配置 IdP 行为一致不依赖各 IdP 自身的 scope 语义。应用 scope 会在 OAuth 元数据中公布以便客户端请求把它们加入default_scopes可让动态注册的客户端默认请求它们即默认勾选。用required_scopes来门禁端点本身rxe.MCPPlugin(app_scopes{...}, required_scopes[orders:read])Bearer 令牌必须携带这些 scope 才能触达 MCP 端点。匿名令牌不携带任何 scope所以设置required_scopes的同时也禁用了匿名访问。感知来源的鉴权检查Surface-aware auth checks授予的 scope 在你自己的auth检查中强制执行。每个鉴权上下文——事件、var、页面——都携带请求到达时经过的表面以及为它中介的令牌所携带的 scopectx.surface——browser普通 websocket 路径、event_apiREST 插件或mcpctx.token_scopes—— 浏览器请求为None用户拥有全部权限无令牌限制API 请求为元组OAuth 令牌是同意授予的 scope匿名会话则是()。使用原则是限制性使用当访问是令牌中介时要求 scope并且永远不要把 scope 视为授予比用户在浏览器中能做的更多import reflex as rx import reflex_enterprise as rxe def can_write_orders(ctx) - bool: # 浏览器用户保持正常权限Agent 需要授予的 scope。 return ctx.token_scopes is None or orders:write in ctx.token_scopes def browser_only(ctx) - bool: return ctx.surface browser class OrderState(rx.State): rxe.event(authcan_write_orders) def place_order(self, item_id: str): ... rxe.event(authbrowser_only) def export_everything(self): ...这是刻意设计的身份 表面双重判定同一个已登录用户在浏览器中保持全部权限而他委派的 Agent 仅被限制在同意屏上勾选的范围内。从源码结构看auth检查的完整语义三种取值True/False/可调用检查以及检查仅在认证成功后运行的规则与 Secure by Default 文档中描述的四类包装器rxe.page/rxe.event/rxe.field/rxe.var一致。限流三种限流器与按处理器覆盖按令牌的调用限流每一个 MCP 调用——包括工具和会话读取类资源——都会计入出示的会话令牌call_rate_limit每call_rate_window默认每分钟 60 次按进程跟踪。超出时返回清晰的 retry-after 错误。浏览器websocket事件永不受此机制限流。按处理器覆盖预算个别处理器可以在默认值不合适的场景覆盖自己的预算class ReportState(rx.State): rxe.event(rate_limit2, rate_limit_window60.0) def generate_expensive_report(self): ... rxe.event(rate_limit0) # 从按令牌限流中豁免 def cheap_ping(self): ...被覆盖的处理器计入它自己的按令牌桶其余所有调用共享该令牌的默认桶。两个按 IP 的限流器限流器默认键控依据保护对象registration_rate_limit10 / 60s客户端 IPRFC 7591 动态客户端注册——匿名调用者唯一可写入的 OAuth 端点。token_rate_limit10 / 60s客户端 IP匿名会话授权每次授权都会播种消耗内存的服务端会话。call_rate_limit60 / 60s会话令牌MCP 与 REST 调用支持按处理器rxe.event(rate_limit...)覆盖。数据来源docs/enterprise/mcp/deployment.md 的限流表格与认证文档中的token_rate_limit/call_rate_limit描述一致。任何一项设为0都会禁用该限流器——生产环境不推荐这样做。生产部署要点MCP 端点是面向 Agent 的、携带凭证的表面。在它面对 localhost 之外的任何流量之前有四件事需要处理详见 生产部署指南TLS 必须启用OAuth 授权服务器发放的是 Bearer 凭证重定向 URL 上的授权码、令牌端点上的 access/refresh 令牌明文 HTTP 下可被任何路径上的观察者读取与重放。接线时强制执行MCP OAuth 启用后解析出的 issuerissuer_url或 config 的deploy_url/api_url若是非回环主机的明文http启动即抛ConfigErrorhttp://localhost、http://127.0.0.1、http://[::1]仍被允许以支持本地开发。匿名令牌端点与 REST API 同样每请求携带 Bearer即使关闭 OAuth 也需要同样的 TLS 保护。issuer 源与可信代理跳数issuer_url必须是代理服务的公共https源站OAuth 发现文档会把它内嵌值错误会产出客户端无法跟随的元数据registration_trusted_proxy_hops用于按 IP 限流器解析真实客户端地址默认0完全忽略X-Forwarded-For直连场景下该头是攻击者可控的。令牌存储配置了redis_url时令牌、待处理授权、同意记录与上传票据存于Redis否则存于进程内存。内存存储不跨重启、不跨 worker 共享多 worker 或生产环境务必配置 Redis要求Redis 6.2存储依赖GETDEL实现一次性授权码启动时探测版本不满足则快速失败。可显式覆盖为MCPPlugin(auth_store...)。每应用只能有一个启用 OAuth 的 MCP 挂载OAuth 外观每进程只绑定一个授权服务器第二个启用 OAuth 的MCPPlugin会遮蔽第一个接线时抛ConfigError额外的 MCP 表面可以用authFalse以纯匿名会话运行。此外安全清单还强调默认暴露所有应用事件处理器务必备份auth门禁或expose_eventsFalse状态读取会从routervar 中剥离服务端的client_token/session_id同意路由的反框架头在前端分离部署时需由 CDN 补充。结语Reflex Enterprise 的 MCP 认证把Agent 可编程访问与人类授权的安全边界统一在一套模型里匿名会话令牌让无需身份的 Agent 零摩擦接入OAuth 2.1 授权服务器则让以用户身份行动的 Agent 严格限制在同意页勾选的 scope 内而ctx.surface/ctx.token_scopes让每个auth检查都能区分浏览器用户与委派 Agent并施加不同权限。配合按 IP、按令牌的三重限流与 Redis 存储这一认证模型从开发到生产都保持行为一致、可审计、可收紧。延伸阅读Auto MCP 总览MCP 端点、工具、资源与全部MCPPlugin配置参数参考。自定义 MCP 资源rxe.mcp.resource只读、参数化的会话状态视图。生产部署指南TLS 要求、令牌存储与反向代理配置。Event Handler API同一套处理器表面经 REST OpenAPI 暴露。Secure by Defaultauth检查如何作用于页面、处理器、字段与 var。Auth 认证总览AuthPlugin及其默认安全行为。【免费下载链接】reflex️ Web apps in pure Python 项目地址: https://gitcode.com/GitHub_Trending/re/reflex创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表