十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

TypeSpec Python 客户端的 OAuth 2.0 凭据支持:从 TypeSpec 声明到自定义凭据实现

TypeSpec Python 客户端的 OAuth 2.0 凭据支持:从 TypeSpec 声明到自定义凭据实现 TypeSpec Python 客户端的 OAuth 2.0 凭据支持从 TypeSpec 声明到自定义凭据实现【免费下载链接】typespec项目地址: https://gitcode.com/GitHub_Trending/ty/typespec本篇技术指南聚焦 TypeSpec Python HTTP 客户端的 OAuth 2.0 凭据机制如何在.tsp文件中用useAuth(OAuth2Auth...)声明 OAuth 2.0 认证流如何编写实现了get_token_info方法的自定义凭据类以对接生成客户端的 Bearer Token 认证策略并深入 TypeSpec Python 生成器的源码讲清auth_flows从 TypeSpec 声明、emitter 建模到生成代码注入的完整链路。读完本篇你可以为任意生成的 Python 客户端端到端接入 client credentials 或 authorization code 两种 OAuth 2.0 流程。一、整体机制TypeSpec 声明 运行时自定义凭据TypeSpec 的 Python 客户端由packages/http-client-python包生成将认证声明与凭据实现解耦声明侧在 TypeSpec 文件中用useAuth(OAuth2Auth...)装饰器描述 OAuth 2.0 授权流flow 类型、授权端点、token 端点、scopes。运行时侧用户提供一个实现了get_token_info方法的凭据对象遵循 corehttp 包定义的凭据接口返回AccessTokenInfo生成客户端在发送请求前自动向该凭据获取 access token并以 Bearer 头形式附加到 HTTP 请求上。这种设计的核心收益是TypeSpec 负责声明需要什么样的认证scopes、端点、流程类型会被生成到客户端配置中而怎么拿到 token由使用者按自己的身份提供商实现官方示例给出了 client credentials 与 authorization code 两种流程的参考实现OAuth 2.0 指南原文client credentials 示例凭据authorization code 示例凭据二、第一步在 TypeSpec 中声明 OAuth 2.0在.tsp文件中对目标接口声明 OAuth 2.0 认证。以 client credentials 流程为例指南原文示例useAuth(OAuth2Auth[ { type: OAuth2FlowType.clientCredentials, authorizationUrl: https://auth.example.com/authorize, tokenUrl: https://auth.example.com/token, scopes: [read, write], } ] )关键字段说明字段含义type流程类型OAuth2FlowType.clientCredentials表示客户端凭据流程OAuth 2.0 还支持OAuth2FlowType.authorizationCode、OAuth2FlowType.implicit等可组合成数组声明多个 flowauthorizationUrl授权端点 URL会随auth_flows一起下发给运行时凭据供其获取 tokentokenUrltoken 端点 URLscopes该流程所需的作用域列表生成客户端时会把所有 flow 的 scopes 汇总为credentialScopesOAuth2Auth...的参数是流程对象数组因此可以同时声明多种流程运行时凭据通过options参数中的auth_flows自行选择需要的那一个详见第四节。三、第二步实现 OAuth2 凭据类生成客户端要求传入的凭据实现get_token_info方法接受可变数量的 scope 参数和可选的optionsTokenRequestOptions返回一个AccessTokenInfo对象。下面结合仓库中的两个参考实现逐段拆解。3.1 client credentials 流程实现完整示例见 oauth2_client_credential.py核心逻辑如下from typing import Any, Optional import time import httpx from corehttp.credentials import AccessTokenInfo, TokenRequestOptions class OAuth2ClientCredential: A credential that uses client ID and client secret to authenticate. This credential acquires tokens via client credentials flow. :param str client_id: The client ID of the application. :param str client_secret: The client secret of the application. def __init__(self, client_id: str, client_secret: str, **kwargs: Any): self.client_id client_id self.client_secret client_secret self.authority_url kwargs.get(authority_url) def get_token_info( self, *scopes: str, options: Optional[TokenRequestOptions] None ) - AccessTokenInfo: if not scopes: raise ValueError(At least one scope must be provided.) authority_url None auth_flows options.get(auth_flows) # If there was at least one flow in the TypeSpec, pick the first one. # If your TypeSpec has several flows, you may want to loop to find the one you need if auth_flows: auth_flow auth_flows[0] authority_url auth_flow.get(authorizationUrl) authority_url authority_url or self.authority_url if not authority_url: raise ValueError( No authority URL provided. Provide it in the constructor or in the options. ) # Prepare the token request data {scope: .join(scopes), grant_type: client_credentials} with httpx.Client() as client: response client.post( authority_url, auth(self.client_id, self.client_secret), datadata ) response.raise_for_status() token response.json().get(access_token) expires_in response.json().get(expires_in) expires_on time.time() expires_in return AccessTokenInfo(token, expires_on)要点解析凭据参数构造函数接收client_id与client_secret并通过**kwargs可选接收authority_urltoken 端点 URL——如果不在构造时提供则要求从options的auth_flows中获取否则抛出ValueError。scopes 校验get_token_info至少要有一个 scope否则直接报错。scopes 即调用方生成的客户端认证策略根据 TypeSpec 中声明的credentialScopes传入的作用域可能与 auth flow 中定义的 scopes 重复。auth_flows的取舍策略示例直接取auth_flows[0]TypeSpec 中声明的第一个 flow并用其authorizationUrl作为发起 token 请求的端点如果 TypeSpec 中声明了多个 flow注释明确提示应自行遍历查找所需 flow。token 请求细节grant_type固定为client_credentialsscope为各 scope 以空格连接使用 HTTP Basic 认证携带client_id:client_secret响应按 OAuth 2.0 标准取access_token与expires_in将expires_in秒数换算为expires_onUnix 时间戳后构造AccessTokenInfo(token, expires_on)返回。3.2 authorization code 流程实现oauth2_auth_code_credential.py 给出授权码流程的对应实现与 client credentials 版本的差异在于构造函数要求client_id和authorization_codeauthority_url、redirect_uri、client_secret均为可选关键字参数token 请求的grant_type为authorization_code请求体额外携带code授权码若设置了redirect_uri则一并提交仅当提供了client_secret时才使用 Basic 认证auth(self.client_id, self.client_secret) if self.client_secret else None以兼容公共客户端public client场景。# authorization code 流程的 token 请求体构造摘自示例 data { scope: .join(scopes), grant_type: authorization_code, code: self.authorization_code, } if self.redirect_uri: data[redirect_uri] self.redirect_uri两个示例共同体现了指南的核心契约凭据类只需实现get_token_info并返回AccessTokenInfo即可被生成的 Python 客户端消费无需修改生成代码。四、auth_flows的生成链路从 TypeSpec 到客户端配置自定义凭据之所以能拿到 TypeSpec 中声明的授权端点是因为生成器把 OAuth 2.0 的 flows 完整传递到了运行时的认证策略中。这条链路在源码中可以完整追溯4.1 emitter 侧OAuth2 方案映射为 BearerTokenCredentialPolicy在 Python 客户端 emitter 的类型建模逻辑中TypeSpec 的oauth2认证方案被转换为BearerTokenCredentialPolicy策略描述并汇总所有 flow 的 scopes 到credentialScopes// packages/http-client-python/emitter/src/types.ts if (scheme.type oauth2) { credential_type { type: OAuth2, policy: { type: BearerTokenCredentialPolicy, credentialScopes: [], flows: (context.emitContext.options as any).flavor azure ? [] : scheme.flows, }, }; for (const flow of scheme.flows) { for (const scope of flow.scopes) { credential_type.policy.credentialScopes.push(scope.value); } } }见 types.ts。注意一个适用前提当 emitter 以 azure flavor 运行时flows会被置空Azure 场景下凭据端点由 Azure 核心库约定不依赖 TypeSpec 声明的 flows而通用unbranded场景下flows会原样传递这正是上文示例凭据能读到authorizationUrl的来源。4.2 codegen 侧策略初始化代码的生成生成代码构建阶段BearerTokenCredentialPolicyType负责把上述模型渲染为客户端配置文件中的策略初始化调用# packages/http-client-python/generator/pygen/codegen/models/credential_types.py def call(self, async_mode: bool) - str: policy_name f{Async if async_mode else }BearerTokenCredentialPolicy auth_flows fauth_flows{self.flows}, if self.flows else return fpolicies.{policy_name}(self.credential, *self.credential_scopes, {auth_flows}**kwargs)见 credential_types.py。这段代码揭示了三个事实生成的客户端在同步/异步模式下分别使用BearerTokenCredentialPolicy/AsyncBearerTokenCredentialPolicy凭据对象你在构造客户端时传入的那个与 TypeSpec 声明的 scopes 一起注入策略auth_flows{flows}以字面量形式写入策略初始化调用——这就是get_token_info的options参数中出现auth_flows键的根源。4.3 测试佐证auth_flows最终落在authentication_policy._auth_flowsmock API 的回归测试直接断言了该链路的结果生成的 OAuth2 客户端配置中的认证策略会持有与 TypeSpec 声明一致的_auth_flows列表含authorizationUrl、scopes、type字段# packages/http-client-python/tests/mock_api/unbranded/test_auth_flow.py def test_oauth2_auth_flows(): oauth2_client OAuth2Client(fake_credential) assert oauth2_client._config.authentication_policy._auth_flows [ { authorizationUrl: https://login.microsoftonline.com/common/oauth2/authorize, scopes: [{value: https://security.microsoft.com/.default}], type: implicit, } ]见 test_auth_flow.py。同一测试目录下的 test_authentication.py 中的FakeCredentialfixture 也演示了与示例凭据一致的get_token_info契约——返回core_library.credentials.AccessTokenInfo(token..., expires_on...)——可以作为编写自己凭据时的最小参考。五、第三步将凭据接入生成的客户端凭据实现完成后把它作为构造参数传给生成的客户端即可指南原文示例credential MyOAuth2Credential() client MyGeneratedClient(endpoint, credential) result client.my_operation() print(result)客户端每次发起需要认证的请求时认证策略会调用凭据的get_token_infoscopes 来自 TypeSpec 声明把返回的 token 以 Bearer 形式附加到请求头上。以第二节的OAuth2ClientCredential为例接入方式即from docs.samples_client_python_oauth_oauth2_client_credential import OAuth2ClientCredential # 示意导入按实际包结构调整 credential OAuth2ClientCredential(client_id..., client_secret...) client MyGeneratedClient(https://api.example.com, credential)六、小结环节位置职责声明 OAuth 2.0.tsp文件useAuth(OAuth2Auth[...] )声明流程类型、端点与 scopesemitter 建模types.ts将 oauth2 方案映射为BearerTokenCredentialPolicy汇总credentialScopes、透传flows代码生成credential_types.py生成携带auth_flows的策略初始化代码运行时凭据client credentials 示例 / auth code 示例实现get_token_info向身份提供商换取 token 并返回AccessTokenInfo验证test_auth_flow.py断言生成客户端策略持有正确的auth_flows掌握以上链路后你可以为任意 OAuth 2.0 身份提供商自研 IdP、企业 SSO 等编写符合 corehttp 凭据接口的get_token_info实现并直接注入 TypeSpec 生成的 Python 客户端完成端到端的认证接入。需要注意的适用前提auth_flows仅在非 azure flavor 的通用场景下由 emitter 透传多 flow 声明时需自定义凭据自行遍历选择目标流程。【免费下载链接】typespec项目地址: https://gitcode.com/GitHub_Trending/ty/typespec创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表