Files
jiu/client/lib/core/utils/web_launch.dart
T
wangjia a773a33779 feat: App→网页免登录(一次性换票 SSO)——移动/桌面点链接直达已登录官网
- backend:POST /auth/web-ticket(需登录,签 60s 单次票据,每用户限频)+
  POST /auth/web-ticket/exchange(公开,原子即焚兑换正常登录态,响应同
  /auth/login 另带 shop_code);web_tickets 新表 + user_sessions.kind 列
  (sso 会话:web 平台、refresh 12h 硬到期、不占设备并发配额、设备管理可见
  可踢);清理任务顺带清过期票据;schema.sql/AutoMigrate/testutil 同步
- web:/sso 落地页——兑票写入与 Web 版共享的 localStorage 后跳 redirect;
  redirect 白名单只收本站相对路径(防 open redirect),票据即时从地址栏抹除
- client:launchAuthedWebPath(ref, path) 封装(签票→拼 /sso URL→launchUrl,
  失败降级未登录直开;桌面/移动同一套);授权面板「查看套餐价格」接入

test(backend): web_ticket_test 三用例(兑换+续期/单次即焚/过期拒绝/
sso 不占配额双向验证)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 21:30:08 +08:00

27 lines
1.2 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// core/utils/web_launch.dart — App→官网免登录跳转(一次性换票 SSO)。
// 先向后端签一张 60s 单次票据,再打开 官网/sso?t=<票>&redirect=<路径>
// 落地页兑票写入登录态后跳目标页——桌面/移动同一套(launchUrl 跨端)。
// 签票失败(未登录/网络异常)时降级为直接打开目标链接(未登录态浏览)。
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:url_launcher/url_launcher.dart';
import '../api/api_client.dart';
import '../config/app_config.dart';
/// 打开官网 [path](如 `/#pricing`、`/profile/`)并自动登录。
Future<void> launchAuthedWebPath(WidgetRef ref, String path) async {
final base = AppConfig.publicBaseUrl;
Uri target = Uri.parse('$base$path');
try {
final resp = await ref.read(apiClientProvider).post('/auth/web-ticket');
final ticket = resp.data?['data']?['ticket'] as String?;
if (ticket != null && ticket.isNotEmpty) {
target = Uri.parse(
'$base/sso/?t=$ticket&redirect=${Uri.encodeComponent(path)}');
}
} catch (_) {
// 签票失败降级:未登录态直开目标页
}
await launchUrl(target, mode: LaunchMode.externalApplication);
}