@liujitcn/kratos-uni-app-core 0.0.38 → 0.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @liujitcn/kratos-uni-app-core
2
2
 
3
+ 账号密码、OAuth 票据兑换和微信登录统一返回 `mfa_remember_days`,表示当前登录策略允许的 MFA 设备免验证天数;为 `0` 时不提供记住设备选项。
4
+
3
5
  `@liujitcn/kratos-uni-app-core` 是应用底座包,提供模块协议、启动流程、动态导航、认证与请求、MFA 校验、共享状态、基础页面和构建期页面装配能力。业务模块只能通过本包公开 exports 使用这些能力。
4
6
 
5
7
  ## 目录结构
package/dist/module.mjs CHANGED
@@ -61,10 +61,10 @@ var zh_CN_default = {
61
61
  "core.home.account_capability_description": "\u4E2A\u4EBA\u8D44\u6599\u3001\u5E94\u7528\u8BBE\u7F6E\u4E0E\u667A\u80FD\u52A9\u624B\u5165\u53E3\u5DF2\u4FDD\u7559",
62
62
  "core.home.cross_platform": "\u8DE8\u7AEF\u9875\u9762",
63
63
  "core.home.cross_platform_description": "\u540C\u4E00\u5957\u9875\u9762\u4EE3\u7801\u9002\u914D H5 \u548C\u5FAE\u4FE1\u5C0F\u7A0B\u5E8F",
64
- "core.home.demo_scope": "\u6F14\u793A\u8303\u56F4",
64
+ "core.home.demo_scope": "\u529F\u80FD\u6982\u89C8",
65
65
  "core.home.framework": "\u5E94\u7528\u6846\u67B6",
66
66
  "core.home.language": "\u5F00\u53D1\u8BED\u8A00",
67
- "core.home.main_title": "\u5E94\u7528\u6846\u67B6\u793A\u4F8B",
67
+ "core.home.main_title": "\u5E94\u7528\u9996\u9875",
68
68
  "core.home.state_management": "\u72B6\u6001\u7BA1\u7406",
69
69
  "core.home.static_home": "\u9759\u6001\u9996\u9875",
70
70
  "core.home.static_home_description": "\u5F53\u524D\u9996\u9875\u7528\u4E8E\u5C55\u793A\u6846\u67B6\u4FE1\u606F\uFF0C\u4E0D\u4F9D\u8D56\u4E1A\u52A1\u63A5\u53E3",
@@ -88,6 +88,7 @@ var zh_CN_default = {
88
88
  "core.login.login_success": "\u767B\u5F55\u6210\u529F",
89
89
  "core.login.mfa_title": "\u591A\u56E0\u7D20\u8BA4\u8BC1",
90
90
  "core.login.mfa_code": "\u8BF7\u8F93\u5165\u52A8\u6001\u53E3\u4EE4",
91
+ "core.login.mfa_remember_device": "{days}\u5929\u5185\u514D\u9A8C\u8BC1\u6B64\u8BBE\u5907",
91
92
  "core.login.mfa_recovery_code": "\u6062\u590D\u7801\uFF08\u53EF\u9009\uFF09",
92
93
  "core.login.mfa_setup_title": "\u7ED1\u5B9A\u591A\u56E0\u7D20\u8BA4\u8BC1",
93
94
  "core.login.mfa_copy_uri": "\u590D\u5236\u7ED1\u5B9A\u5730\u5740",
@@ -204,10 +205,10 @@ var en_US_default = {
204
205
  "core.home.account_capability_description": "Profile, app settings, and AI assistant access are included",
205
206
  "core.home.cross_platform": "Cross-platform pages",
206
207
  "core.home.cross_platform_description": "One codebase for H5 and WeChat Mini Program",
207
- "core.home.demo_scope": "Demo scope",
208
+ "core.home.demo_scope": "Overview",
208
209
  "core.home.framework": "App framework",
209
210
  "core.home.language": "Language",
210
- "core.home.main_title": "Application Framework",
211
+ "core.home.main_title": "Application Home",
211
212
  "core.home.state_management": "State management",
212
213
  "core.home.static_home": "Static home",
213
214
  "core.home.static_home_description": "This page presents framework details without business APIs",
@@ -229,6 +230,7 @@ var en_US_default = {
229
230
  "core.login.captcha_write_failed": "Failed to save verification image",
230
231
  "core.login.default_sub_title": "Welcome",
231
232
  "core.login.login_success": "Logged in",
233
+ "core.login.mfa_remember_device": "Skip verification on this device for {days} days",
232
234
  "core.login.mfa_title": "Multi-factor authentication",
233
235
  "core.login.mfa_code": "Enter the authenticator code",
234
236
  "core.login.mfa_recovery_code": "Recovery code (optional)",
@@ -347,10 +349,10 @@ var ja_JP_default = {
347
349
  "core.home.account_capability_description": "\u500B\u4EBA\u60C5\u5831\u3001\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u8A2D\u5B9A\u3001\u30B9\u30DE\u30FC\u30C8\u30A2\u30B7\u30B9\u30BF\u30F3\u30C8\u5165\u53E3\u304C\u4E88\u7D04\u3055\u308C\u3066\u3044\u307E\u3059",
348
350
  "core.home.cross_platform": "\u30AF\u30ED\u30B9\u30A8\u30F3\u30C9 \u30DA\u30FC\u30B8",
349
351
  "core.home.cross_platform_description": "\u540C\u3058\u30DA\u30FC\u30B8 \u30B3\u30FC\u30C9 \u30BB\u30C3\u30C8\u304C H5 \u304A\u3088\u3073 WeChat \u30DF\u30CB \u30D7\u30ED\u30B0\u30E9\u30E0\u306B\u9069\u5FDC\u3057\u307E\u3059",
350
- "core.home.demo_scope": "\u30C7\u30E2\u306E\u7BC4\u56F2",
352
+ "core.home.demo_scope": "\u6A5F\u80FD\u6982\u8981",
351
353
  "core.home.framework": "\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3 \u30D5\u30EC\u30FC\u30E0\u30EF\u30FC\u30AF",
352
354
  "core.home.language": "\u958B\u767A\u8A00\u8A9E",
353
- "core.home.main_title": "\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u30D5\u30EC\u30FC\u30E0\u30EF\u30FC\u30AF\u306E\u4F8B",
355
+ "core.home.main_title": "\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u30DB\u30FC\u30E0",
354
356
  "core.home.state_management": "\u30B9\u30C6\u30FC\u30BF\u30B9\u7BA1\u7406",
355
357
  "core.home.static_home": "\u9759\u7684\u30DB\u30FC\u30E0\u30DA\u30FC\u30B8",
356
358
  "core.home.static_home_description": "\u73FE\u5728\u306E\u30DB\u30FC\u30E0\u30DA\u30FC\u30B8\u306F\u30D5\u30EC\u30FC\u30E0\u60C5\u5831\u3092\u8868\u793A\u3059\u308B\u305F\u3081\u306B\u4F7F\u7528\u3055\u308C\u3066\u304A\u308A\u3001\u30D3\u30B8\u30CD\u30B9 \u30A4\u30F3\u30BF\u30FC\u30D5\u30A7\u30A4\u30B9\u306B\u306F\u4F9D\u5B58\u3057\u3066\u3044\u307E\u305B\u3093",
@@ -372,6 +374,7 @@ var ja_JP_default = {
372
374
  "core.login.captcha_write_failed": "\u691C\u8A3C\u30B3\u30FC\u30C9\u30A4\u30E1\u30FC\u30B8\u306E\u66F8\u304D\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
373
375
  "core.login.default_sub_title": "\u3053\u306E\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u3078\u3088\u3046\u3053\u305D",
374
376
  "core.login.login_success": "\u30ED\u30B0\u30A4\u30F3\u306B\u6210\u529F\u3057\u307E\u3057\u305F",
377
+ "core.login.mfa_remember_device": "\u3053\u306E\u7AEF\u672B\u3067\u306F{days}\u65E5\u9593\u3001\u8FFD\u52A0\u8A8D\u8A3C\u3092\u7701\u7565\u3059\u308B",
375
378
  "core.login.mfa_title": "\u591A\u8981\u7D20\u8A8D\u8A3C",
376
379
  "core.login.mfa_code": "\u8A8D\u8A3C\u30B3\u30FC\u30C9\u3092\u5165\u529B",
377
380
  "core.login.mfa_recovery_code": "\u30EA\u30AB\u30D0\u30EA\u30FC\u30B3\u30FC\u30C9\uFF08\u4EFB\u610F\uFF09",
@@ -490,10 +493,10 @@ var zh_TW_default = {
490
493
  "core.home.account_capability_description": "\u500B\u4EBA\u8CC7\u6599\u3001\u61C9\u7528\u8A2D\u5B9A\u8207\u667A\u6167\u52A9\u624B\u5165\u53E3\u5DF2\u4FDD\u7559",
491
494
  "core.home.cross_platform": "\u8DE8\u7AEF\u9801\u9762",
492
495
  "core.home.cross_platform_description": "\u540C\u4E00\u5957\u9801\u9762\u7A0B\u5F0F\u78BC\u9069\u914D H5 \u548C\u5FAE\u4FE1\u5C0F\u7A0B\u5F0F",
493
- "core.home.demo_scope": "\u6F14\u793A\u7BC4\u570D",
496
+ "core.home.demo_scope": "\u529F\u80FD\u6982\u89BD",
494
497
  "core.home.framework": "\u61C9\u7528\u6846\u67B6",
495
498
  "core.home.language": "\u958B\u767C\u8A9E\u8A00",
496
- "core.home.main_title": "\u61C9\u7528\u6846\u67B6\u793A\u4F8B",
499
+ "core.home.main_title": "\u61C9\u7528\u9996\u9801",
497
500
  "core.home.state_management": "\u72C0\u614B\u7BA1\u7406",
498
501
  "core.home.static_home": "\u975C\u614B\u9996\u9801",
499
502
  "core.home.static_home_description": "\u7576\u524D\u9996\u9801\u7528\u65BC\u5C55\u793A\u6846\u67B6\u8CC7\u8A0A\uFF0C\u4E0D\u4F9D\u8CF4\u696D\u52D9\u4ECB\u9762",
@@ -515,6 +518,7 @@ var zh_TW_default = {
515
518
  "core.login.captcha_write_failed": "\u9A57\u8B49\u78BC\u5716\u7247\u5BEB\u5165\u5931\u6557",
516
519
  "core.login.default_sub_title": "\u6B61\u8FCE\u4F7F\u7528\u672C\u61C9\u7528",
517
520
  "core.login.login_success": "\u767B\u5165\u6210\u529F",
521
+ "core.login.mfa_remember_device": "{days}\u5929\u5167\u514D\u9A57\u8B49\u6B64\u88DD\u7F6E",
518
522
  "core.login.mfa_title": "\u591A\u56E0\u7D20\u8A8D\u8B49",
519
523
  "core.login.mfa_code": "\u8ACB\u8F38\u5165\u52D5\u614B\u5BC6\u78BC",
520
524
  "core.login.mfa_recovery_code": "\u6062\u5FA9\u78BC\uFF08\u53EF\u9078\uFF09",
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "type": "git",
8
8
  "url": "git@github.com:liujitcn/kratos-admin.git"
9
9
  },
10
- "version": "0.0.38",
10
+ "version": "0.0.39",
11
11
  "type": "module",
12
12
  "files": [
13
13
  "dist",
@@ -35,10 +35,10 @@
35
35
  "core.home.account_capability_description": "Profile, app settings, and AI assistant access are included",
36
36
  "core.home.cross_platform": "Cross-platform pages",
37
37
  "core.home.cross_platform_description": "One codebase for H5 and WeChat Mini Program",
38
- "core.home.demo_scope": "Demo scope",
38
+ "core.home.demo_scope": "Overview",
39
39
  "core.home.framework": "App framework",
40
40
  "core.home.language": "Language",
41
- "core.home.main_title": "Application Framework",
41
+ "core.home.main_title": "Application Home",
42
42
  "core.home.state_management": "State management",
43
43
  "core.home.static_home": "Static home",
44
44
  "core.home.static_home_description": "This page presents framework details without business APIs",
@@ -60,6 +60,7 @@
60
60
  "core.login.captcha_write_failed": "Failed to save verification image",
61
61
  "core.login.default_sub_title": "Welcome",
62
62
  "core.login.login_success": "Logged in",
63
+ "core.login.mfa_remember_device": "Skip verification on this device for {days} days",
63
64
  "core.login.mfa_title": "Multi-factor authentication",
64
65
  "core.login.mfa_code": "Enter the authenticator code",
65
66
  "core.login.mfa_recovery_code": "Recovery code (optional)",
@@ -35,10 +35,10 @@
35
35
  "core.home.account_capability_description": "個人情報、アプリケーション設定、スマートアシスタント入口が予約されています",
36
36
  "core.home.cross_platform": "クロスエンド ページ",
37
37
  "core.home.cross_platform_description": "同じページ コード セットが H5 および WeChat ミニ プログラムに適応します",
38
- "core.home.demo_scope": "デモの範囲",
38
+ "core.home.demo_scope": "機能概要",
39
39
  "core.home.framework": "アプリケーション フレームワーク",
40
40
  "core.home.language": "開発言語",
41
- "core.home.main_title": "アプリケーションフレームワークの例",
41
+ "core.home.main_title": "アプリケーションホーム",
42
42
  "core.home.state_management": "ステータス管理",
43
43
  "core.home.static_home": "静的ホームページ",
44
44
  "core.home.static_home_description": "現在のホームページはフレーム情報を表示するために使用されており、ビジネス インターフェイスには依存していません",
@@ -60,6 +60,7 @@
60
60
  "core.login.captcha_write_failed": "検証コードイメージの書き込みに失敗しました",
61
61
  "core.login.default_sub_title": "このアプリケーションへようこそ",
62
62
  "core.login.login_success": "ログインに成功しました",
63
+ "core.login.mfa_remember_device": "この端末では{days}日間、追加認証を省略する",
63
64
  "core.login.mfa_title": "多要素認証",
64
65
  "core.login.mfa_code": "認証コードを入力",
65
66
  "core.login.mfa_recovery_code": "リカバリーコード(任意)",
@@ -35,10 +35,10 @@
35
35
  "core.home.account_capability_description": "个人资料、应用设置与智能助手入口已保留",
36
36
  "core.home.cross_platform": "跨端页面",
37
37
  "core.home.cross_platform_description": "同一套页面代码适配 H5 和微信小程序",
38
- "core.home.demo_scope": "演示范围",
38
+ "core.home.demo_scope": "功能概览",
39
39
  "core.home.framework": "应用框架",
40
40
  "core.home.language": "开发语言",
41
- "core.home.main_title": "应用框架示例",
41
+ "core.home.main_title": "应用首页",
42
42
  "core.home.state_management": "状态管理",
43
43
  "core.home.static_home": "静态首页",
44
44
  "core.home.static_home_description": "当前首页用于展示框架信息,不依赖业务接口",
@@ -62,6 +62,7 @@
62
62
  "core.login.login_success": "登录成功",
63
63
  "core.login.mfa_title": "多因素认证",
64
64
  "core.login.mfa_code": "请输入动态口令",
65
+ "core.login.mfa_remember_device": "{days}天内免验证此设备",
65
66
  "core.login.mfa_recovery_code": "恢复码(可选)",
66
67
  "core.login.mfa_setup_title": "绑定多因素认证",
67
68
  "core.login.mfa_copy_uri": "复制绑定地址",
@@ -35,10 +35,10 @@
35
35
  "core.home.account_capability_description": "個人資料、應用設定與智慧助手入口已保留",
36
36
  "core.home.cross_platform": "跨端頁面",
37
37
  "core.home.cross_platform_description": "同一套頁面程式碼適配 H5 和微信小程式",
38
- "core.home.demo_scope": "演示範圍",
38
+ "core.home.demo_scope": "功能概覽",
39
39
  "core.home.framework": "應用框架",
40
40
  "core.home.language": "開發語言",
41
- "core.home.main_title": "應用框架示例",
41
+ "core.home.main_title": "應用首頁",
42
42
  "core.home.state_management": "狀態管理",
43
43
  "core.home.static_home": "靜態首頁",
44
44
  "core.home.static_home_description": "當前首頁用於展示框架資訊,不依賴業務介面",
@@ -60,6 +60,7 @@
60
60
  "core.login.captcha_write_failed": "驗證碼圖片寫入失敗",
61
61
  "core.login.default_sub_title": "歡迎使用本應用",
62
62
  "core.login.login_success": "登入成功",
63
+ "core.login.mfa_remember_device": "{days}天內免驗證此裝置",
63
64
  "core.login.mfa_title": "多因素認證",
64
65
  "core.login.mfa_code": "請輸入動態密碼",
65
66
  "core.login.mfa_recovery_code": "恢復碼(可選)",
@@ -24,7 +24,7 @@ export interface OptionLanguageResponse {
24
24
  languages: LanguageItem[];
25
25
  }
26
26
 
27
- /** 语言公共服务。 */
27
+ /** Base语言公共服务。 */
28
28
  export interface LanguageService {
29
29
  /** 查询当前支持的语言选项。 */
30
30
  OptionLanguage(request: OptionLanguageRequest): Promise<OptionLanguageResponse>;
@@ -155,6 +155,8 @@ export interface LoginResponse {
155
155
  mfa_method: string;
156
156
  /** WebAuthn认证选项JSON */
157
157
  mfa_webauthn_options_json: string;
158
+ /** 当前登录策略允许的MFA设备免验证天数 */
159
+ mfa_remember_days: number;
158
160
  }
159
161
 
160
162
  /** Base登录公共服务 */
@@ -19,6 +19,8 @@ export interface VerifyMfaRequest {
19
19
  recovery_code: string;
20
20
  /** WebAuthn认证响应JSON */
21
21
  webauthn_response_json: string;
22
+ /** 是否记住当前设备 */
23
+ remember_device: boolean;
22
24
  }
23
25
 
24
26
  /** 登录强制绑定多因素认证请求。 */
@@ -109,6 +109,8 @@ export interface CreateOauthSessionResponse {
109
109
  mfa_method: string;
110
110
  /** WebAuthn认证选项JSON */
111
111
  mfa_webauthn_options_json: string;
112
+ /** 当前登录策略允许的MFA设备免验证天数 */
113
+ mfa_remember_days: number;
112
114
  }
113
115
 
114
116
  /** 三方登录回调请求 */
@@ -157,6 +159,8 @@ export interface ExchangeOauthTicketResponse {
157
159
  mfa_method: string;
158
160
  /** WebAuthn认证选项JSON */
159
161
  mfa_webauthn_options_json: string;
162
+ /** 当前登录策略允许的MFA设备免验证天数 */
163
+ mfa_remember_days: number;
160
164
  }
161
165
 
162
166
  /** 个人中心三方账号绑定回调请求 */
package/src/utils/http.ts CHANGED
@@ -73,7 +73,7 @@ type HttpRequestOptions = UniApp.RequestOptions & {
73
73
  const httpInterceptor = {
74
74
  // 拦截前触发
75
75
  invoke(options: UniApp.RequestOptions) {
76
- const authMode = (options as HttpRequestOptions).authMode
76
+ const authMode = resolveAuthMode(options as HttpRequestOptions, options.url)
77
77
  // 1. 相对接口地址只拼接一次基础路径,兼容 HMR 等场景下拦截器重复注册。
78
78
  if (
79
79
  !options.url.startsWith('http') &&
@@ -165,9 +165,10 @@ export const http = <T>(options: HttpRequestOptions) => {
165
165
  return new Promise<T>((resolve, reject) => {
166
166
  const sendRequest = async (retriedAsAnonymous = false) => {
167
167
  try {
168
- const requestOptions = { ...options, header: { ...options.header } }
168
+ const requestOptions: HttpRequestOptions = { ...options, header: { ...options.header } }
169
169
  const requestUrl = String(requestOptions.url)
170
170
  const authMode = resolveAuthMode(requestOptions, requestUrl)
171
+ requestOptions.authMode = retriedAsAnonymous && authMode === 'optional' ? 'none' : authMode
171
172
  let accessToken = ''
172
173
  try {
173
174
  accessToken = await getAccessTokenByMode(
@@ -327,6 +328,7 @@ async function refreshAccessToken() {
327
328
  method: 'POST',
328
329
  data: { refresh_token: refreshToken },
329
330
  header: {
331
+ Authorization: 'no-auth',
330
332
  'source-client': sourceClient,
331
333
  ...getLocaleRequestHeaders(),
332
334
  },
@@ -373,7 +375,15 @@ async function refreshAccessToken() {
373
375
  setTokenExpiresIn(expires_in)
374
376
  }
375
377
 
378
+ /** 业务页提示重新登录;登录页只清理残留登录态,避免后台请求触发循环弹窗。 */
376
379
  async function promptRelogin() {
380
+ const pages = getCurrentPages()
381
+ if (pages[pages.length - 1]?.route === 'pages/login/login') {
382
+ if (getToken() || getRefreshToken() || uni.getStorageSync('user')) {
383
+ silentClearAuthData()
384
+ }
385
+ return
386
+ }
377
387
  if (isPromptingRelogin) {
378
388
  return
379
389
  }
@@ -54,6 +54,8 @@ const mfaChallengeId = ref('')
54
54
  const mfaCode = ref('')
55
55
  const mfaRecoveryCode = ref('')
56
56
  const mfaMethod = ref('totp')
57
+ const mfaRememberDays = ref(0)
58
+ const rememberMfaDevice = ref(false)
57
59
  const mfaWebAuthnOptionsJson = ref('')
58
60
  const mfaSetupVisible = ref(false)
59
61
  const mfaSetupTicket = ref('')
@@ -290,6 +292,8 @@ const handleLoginResponse = async (response: LoginResponse) => {
290
292
  mfaCode.value = ''
291
293
  mfaRecoveryCode.value = ''
292
294
  mfaMethod.value = response.mfa_method || 'totp'
295
+ mfaRememberDays.value = response.mfa_remember_days || 0
296
+ rememberMfaDevice.value = false
293
297
  mfaWebAuthnOptionsJson.value = response.mfa_webauthn_options_json || ''
294
298
  mfaVisible.value = true
295
299
  return false
@@ -322,6 +326,7 @@ const verifyMfaLogin = async () => {
322
326
  code: mfaRecoveryCode.value ? '' : mfaCode.value,
323
327
  recovery_code: mfaRecoveryCode.value,
324
328
  webauthn_response_json: webauthnResponseJson,
329
+ remember_device: rememberMfaDevice.value,
325
330
  })
326
331
  mfaVisible.value = false
327
332
  if (await handleLoginResponse(response)) await loginSuccess()