Flutter使用oauth2包如何获取Token响应的非标准自定义字段
Dart oauth2 包低侵入获取Token响应自定义字段方案(适配SMART on FHIR场景)
不需要覆写oauth2包内部私有方法、不需要重写授权逻辑,通过自定义HTTP客户端拦截响应的方案即可实现,侵入性极低,原有授权流程代码几乎不需要改动。
实现步骤
- 编写自定义HTTP客户端包装类,仅拦截发往Token端点的请求,缓存完整响应体后再交还给oauth2包正常处理,示例代码如下:
import 'dart:convert'; import 'package:http/http.dart' as http; class TokenCaptureHttpClient extends http.BaseClient { final http.Client _innerClient = http.Client(); /// 缓存的Token端点完整响应JSON Map<String, dynamic>? rawTokenResponse; @override Future<http.StreamedResponse> send(http.BaseRequest request) async { final streamedResp = await _innerClient.send(request); // 匹配Token端点POST请求,可根据你实际的tokenEndpoint地址调整判断规则 if (request.method == 'POST' && request.url.toString().contains('token')) { final respBody = await streamedResp.stream.bytesToString(); rawTokenResponse = jsonDecode(respBody); // 重构响应对象返回,不影响oauth2包后续解析标准字段 return http.StreamedResponse( Stream.value(respBody.codeUnits), streamedResp.statusCode, headers: streamedResp.headers, reasonPhrase: streamedResp.reasonPhrase, ); } return streamedResp; } }
- 初始化
AuthorizationCodeGrant实例时,将上述自定义客户端传入构造函数的httpClient参数,原有授权逻辑不需要做任何修改:
final captureClient = TokenCaptureHttpClient(); final grant = AuthorizationCodeGrant( yourClientId, authorizationEndpoint, tokenEndpoint, httpClient: captureClient, // 传入自定义拦截客户端 secret: yourClientSecret, ); // 后续照常执行authenticate、handleAuthorizationResponse流程 final authClient = await grant.handleAuthorizationResponse(uri.queryParameters);
- 授权流程完成拿到可用的Client实例后,直接从
captureClient.rawTokenResponse中读取需要的自定义字段即可,patient、need_patient_banner、smart_style_url等SMART启动上下文字段都存在于该原始响应对象中。
补充说明
- 解码accessToken、idToken的JWT载荷拿不到上述字段是正常现象,SMART on FHIR规范中这类启动上下文字段本来就放置在Token响应的顶级节点,不会写入JWT载荷。
- 该方案完全不触碰oauth2包的内部实现,不需要fork修改依赖包,也不会破坏包本身的Token解析、自动刷新等原生能力,后续依赖包升级只要不修改HTTP客户端的传入逻辑,代码就可以正常运行。
- 注意根据自己实际的Token端点地址调整请求匹配规则,避免误拦截其他接口请求,同时读取
rawTokenResponse时做好空判断,兼容Token请求失败的异常场景。
内容的提问来源于stack exchange,提问作者Grey
相关产品推荐
相关产品推荐

