尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Open edX Platform OAuth2 认证实战:获取、校验、刷新与使用 JWT 的完整代码示例

Open edX Platform OAuth2 认证实战:获取、校验、刷新与使用 JWT 的完整代码示例 Open edX Platform OAuth2 认证实战获取、校验、刷新与使用 JWT 的完整代码示例【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform本文基于 Open edX Platform 官方参考文档 auth_code_samples.rst 整理覆盖该平台 OAuth2 认证的完整生命周期使用用户名密码获取 JWTpassword 授权、使用客户端凭证获取 JWTclient_credentials 授权、校验 JWT 是否过期、用 refresh token 刷新令牌以及携带 JWT 请求头调用 LMS REST API。读完后你可以直接用文档中的 Python 示例对接 Open edX 的http://lms/oauth2/access_token端点并理解每个请求参数、响应字段access_token、refresh_token、scope等与底层端点实现之间的对应关系。安全警告令牌即秘密官方文档在开头就给出了明确警告Access Token、Refresh Token 和 Client Secret 一般被视为秘密信息不应出现在你的代码中。文档之所以把它们打印出来只是为了让示例完整可用。在生产环境中你不应当向任何不可信的系统或客户端暴露这些令牌。下文的示例沿用了文档原样实际落地时请自行替换为环境变量或密钥管理方案注入的凭证。端点与路由/oauth2/access_token 从哪里来在动手前先确认示例中反复出现的 URLhttp://lms.example.com/oauth2/access_token在仓库中的真实来源LMS 主路由文件 lms/urls.py 将/oauth2/前缀挂载到openedx.core.djangoapps.oauth_dispatch应用并附带注释提醒开发者应当使用这组包装过的路由以兼容现有客户端代码oauth_dispatch/urls.py 中定义了三个核心端点authorize授权页、access_token签发令牌对应本文所有示例的 POST 目标和revoke_token吊销令牌底层由 django-oauth-toolkitoauth2_provider驱动应用模型由设置项OAUTH2_PROVIDER_APPLICATION_MODEL oauth2_provider.Application指定见 openedx/envs/common.py。此外针对历史上/oauth2/access_token/曾遭受攻击导致 LMS 宕机的情况平台对该端点内置了速率限制lms/envs/common.py 中RATELIMIT_ENABLE True与RATELIMIT_RATE 120/m表示默认每 IP 每分钟最多 120 次请求。批量获取令牌时需注意这一限制。示例一使用用户名和密码获取 JWTpassword 授权这是面向交互式登录场景最直接的取令牌方式。请求向oauth2/access_token端点 POST 表单数据其中grant_type为passwordimport requests from pprint import pprint token_request requests.post( fhttp://lms.example.com/oauth2/access_token, data{ client_id: login-service-client-id, grant_type: password, username: test_user, password: test_password, token_type: JWT, }, ) pprint(token_request.json())成功时返回如下结构示例输出取自原文档{access_token: eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiAibG1zLWtleSIsICJleHAiOiAxNjkyMjExNjM4LCAiZ3JhbnRfdHlwZSI6ICJwYXNzd29yZCIsI..., expires_in: 3600, refresh_token: m8iXhVlGABu52xFxVFj5rAz8xSjsRq, scope: read write email profile, token_type: JWT}几个关键字段说明access_token标准三段式 JWTheader.payload.signature示例中 header 声明alg: HS256expires_in: 3600有效期 3600 秒与 JWT payload 中exp与iat相差 1 小时一致refresh_token仅在 password 授权等用户级授权时返回是后续刷新令牌的凭证token_type: JWT声明令牌格式为 JWT调用 API 时请求头需写成Authorization: JWT token。原文档特别强调一条前置条件该方式要求client_id对应的应用Application类型为public。在 Open edX 中OAuth 客户端应用通过 Studio 的 API 应用管理界面或oauth2_provider.Application模型创建confidential 类型客户端必须携带client_secret而 public 客户端可以直接用client_id明文传参。解码示例中的 JWT payload可以看到平台在令牌中携带的用户级 claimsClaim示例值含义audlms-key受众校验 JWT 时需以该值为 audienceisshttp://localhost:18000/oauth2签发方即 LMS 的/oauth2前缀sub用户 UUID资源所有者标识preferred_usernamefeanil登录用户名email/email_verifiedfeanilaxim.org/true邮箱及验证状态nameFeanil Patel显示名scopes[read, write, email, profile]令牌授予的权限范围filters[user:me]服务端 API 过滤提示表示默认只能访问自己的数据is_restrictedfalse是否为受限令牌administrator/superusertrue平台级管理员标志grant_typepassword签发该令牌的授权类型这些 claims 直接决定了令牌能访问哪些 API 以及访问范围是理解 Open edX API 鉴权模型的关键。示例二使用 client_id 与 client_secret 获取 JWTclient_credentials 授权当调用方是服务本身机器对机器而非代表某个具体用户时使用client_credentials授权。客户端凭证通过 HTTP Basic 认证头传递即base64(client_id:client_secret)import base64 import requests from pprint import pprint client_id ukbclQB8aPh7hgsy8ifPXkPf7fRqgUq1w21f2YZa # 注意client_secret 应当真正保密不应硬编码在代码中 # 此处仅为示例演示 client_secret xkN0BJ19q9Jk8UPUppEtC1xe4764c81ioFtlegvokbmnAC7CFCT5gG1Og5nnFmCNc3NHNhUwWWDRVcBfnLSZ4xAlEmSePzfkFtLE06cwR1MuSc0gx9LUEjRrTs3j2vgK credential f{client_id}:{client_secret} encoded_credential base64.b64encode(credential.encode(utf-8)).decode(utf-8) headers {Authorization: fBasic {encoded_credential}, Cache-Control: no-cache} data {grant_type: client_credentials, token_type: jwt} token_request requests.post( http://lms.example.com/oauth2/access_token, headersheaders, datadata ) pprint(token_request.json())返回示例{access_token: eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiAibG1zLWtleSIsICJleHAiOiAxNjkyMjExNjM4LCAiZ3JhbnRfdHlwZSI6ICJjbGllbnQtY3JlZGVudGlhbHMiLCA..., expires_in: 3600, scope: read write email profile, token_type: JWT}与 password 授权的响应相比有两点明显差异没有refresh_token字段。原文档对此有专门说明使用client_credentials获取的 JWT 不会附带 refresh token到期后预期你直接用客户端凭证重新发起一次取令牌请求解码后的 payload 中grant_type为client_credentials且filters为空列表——从该示例的 claims 结构看此类令牌同样携带了用户维度信息sub、preferred_username等具体权限边界取决于应用配置的 scope。另外令牌可用的 scope 并非无限制oauth_dispatch应用通过自定义 scope 后端ApplicationModelScopes见 scopes.py取该应用已配置 scope 默认 scope的交集来约束响应中的scope这解释了为何示例中固定出现read write email profile。校验 JWT 是否过期在把令牌送去调用 API 之前可以在本地快速判断它是否已过期。使用pyjwt库、以签名密钥和受众解码即可import jwt # 参见上文示例获取 JWT token jwt_token token_request.json()[access_token] try: jwt.decode(jwt_token, secret, audiencelms-key, algorithms[HS256]) except jwt.ExpiredSignatureError: # 签名已过期 pass要点audiencelms-key必须与 payload 中的aud一致解码时若不匹配会抛异常algorithms[HS256]需与 header 声明的算法一致secret是 HS256 签名所用的服务端 JWT 密钥仅适合在受控环境如本地开发、脚本校验中使用——再次呼应文档开头的安全警告。使用 Refresh Token 刷新 JWTpassword 授权返回的refresh_token用于在access_token过期后低成本地换发新令牌而不需要用户再次输入密码。刷新请求仍然 POST 到同一个oauth2/access_token端点把grant_type换成refresh_token并带上旧的 refresh tokenimport requests from pprint import pprint # 参见使用用户名和密码获取 JWT响应中包含 refresh_token 属性 refresh_token token_request.json()[refresh_token] refreshed_token_request requests.post( fhttp://lms.example.com/oauth2/access_token, data{ client_id: login-service-client-id, grant_type: refresh_token, refresh_token: token_request.json()[refresh_token], token_type: JWT, }, ) pprint(refreshed_token_request.json())返回示例原文档原样保留{access_token: eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiAibG1zLWtleSIsICJleHAiOiAxNjkyMjE1MTgwLCAiZ3JhbnRfdHlwZSI6ICJwYXNzd29yZCIsICJpYXQiOiAxNjkyMjExNTgwLCA..., expires_in: 3600, token_type: JWT, scope: read write email profile, refresh_token: V5fbgDt2RPVnmI6Q3c6cJ3OjVriGii}注意两点刷新响应中grant_typeclaims 仍标记为password沿用原授权类型但iat/exp已更新为新的时间窗expires_in依旧 3600 秒响应同时返回了一个新的refresh_token意味着 refresh token 是会轮转的——应当保存并覆盖使用最新值而非复用初始令牌。携带 JWT 请求头调用 API拿到有效access_token后调用 LMS 的 REST API 只需在请求头中携带Authorization: JWT token注意 scheme 是JWT而非常见的Bearer。文档以查询当前用户课程注册为例# 参见上文示例获取 JWT token access_token token_request.json()[access_token] enrollment_request requests.get( http://lms.example.com/api/enrollment/v1/enrollment, headers{Authorization: fJWT {access_token}}, ) pprint(enrollment_request.json())示例响应是一条注册记录字段完整体现了 JWT claims 的作用——user对应 payload 中的preferred_usernamefilters: [user:me]决定了该令牌只能查到该用户自己的注册[{course_details: {course_end: None, course_id: course-v1:TestXCourse1, course_modes: [{bulk_sku: None, currency: usd, description: None, expiration_datetime: None, min_price: 0, name: Audit, sku: None, slug: audit, suggested_prices: }], course_name: Open edX Test Course, course_start: 2022-04-09T00:00:00Z, enrollment_end: None, enrollment_start: None, invite_only: False, pacing_type: Instructor Paced}, created: 2023-08-17T14:10:48.476967Z, is_active: True, mode: audit, user: test_user}]适用前提与实践小结所有示例假定 LMS 的 OAuth2 签发端点暴露在http://lms.example.com/oauth2/access_token示例令牌中的iss为http://localhost:18000/oauth2说明文档环境为本地开发栈devstack对接真实站点时请替换域名并改用 HTTPS。四种操作对应同一个端点、不同grant_typepassword需 public 客户端、返回 refresh token、client_credentialsBasic 认证传递凭证、无 refresh token、refresh_token轮转 refresh token令牌过期则本地用pyjwt以audiencelms-key、HS256校验。调用 API 时请求头格式固定为Authorization: JWT access_token。生产环境务必遵守文档开头的安全警告令牌与 secret 不落代码同时留意 lms/envs/common.py 所示的120/m每 IP 速率限制避免脚本高频取令牌被限流。【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表