@nihplod/sso-sdk 1.4.1 → 1.6.0

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.
@@ -58,10 +58,26 @@ interface SsoClientConfig {
58
58
  redirectUri: string;
59
59
  /** SSO 中心地址,如 "https://nihplod.cn" */
60
60
  ssoBaseUrl: string;
61
+ /**
62
+ * 允许 Discovery 文档声明跨源端点(默认 false)。
63
+ *
64
+ * ⚠️ 安全警告:Discovery 文档若被篡改(如中间人/反向代理劫持),攻击者可把
65
+ * token_endpoint 指向自己的服务器窃取 authorization code / refresh_token。
66
+ * SDK 默认校验 authorization_endpoint 必须与 ssoBaseUrl 同源、
67
+ * token_endpoint / userinfo_endpoint 必须与 ssoBaseUrl(或 serverBaseUrl)同源,
68
+ * 不匹配时告警并回退到默认端点。仅当 SSO 中心确实把端点托管在其他域名时
69
+ * 才设置此开关,并自行确保 Discovery 通道可信。
70
+ */
71
+ allowCrossOriginDiscoveryEndpoints?: boolean;
61
72
  /** 请求的 scope(空格分隔),如 "openid profile phone" */
62
73
  scopes?: string;
63
74
  /** RP-Initiated Logout 返回地址(可选)。不传时回退到 redirectUri */
64
75
  postLogoutRedirectUri?: string;
76
+ /**
77
+ * 调试日志开关(默认 false)。开启后输出登录/回调/刷新/登出等关键流程日志,
78
+ * 便于接入方定位问题(生产默认关闭,避免日志噪音)。
79
+ */
80
+ debug?: boolean;
65
81
  /**
66
82
  * 服务端到服务端调用的内网地址(可选,如 http://127.0.0.1:3000)。
67
83
  * 仅用于 discovery / token / userinfo / revocation 等服务器间请求;
@@ -123,11 +139,28 @@ declare class SsoClient {
123
139
  private _discovery;
124
140
  private _discoveryFetchedAt;
125
141
  private _refreshLock;
142
+ /** Discovery 端点 origin 校验失败只告警一次(拒绝的文档不缓存,避免每次调用刷屏) */
143
+ private _discoveryOriginWarned;
126
144
  /** Discovery 文档缓存 TTL(5 分钟) */
127
145
  private static readonly DISCOVERY_TTL_MS;
128
146
  /** Discovery fetch 超时(10 秒) */
129
147
  private static readonly DISCOVERY_TIMEOUT_MS;
130
148
  constructor(config: SsoClientConfig);
149
+ /**
150
+ * 调试日志(config.debug=true 时输出,前缀 [SSO SDK]):
151
+ * 覆盖登录发起 / 回调结果 / 刷新失败 / 登出等关键节点,便于接入方定位问题。
152
+ * 不会输出 token/授权码等敏感值。
153
+ */
154
+ debugLog(...args: unknown[]): void;
155
+ /**
156
+ * 校验 Discovery 文档端点 origin(防文档被篡改后 token/code 被导向攻击者服务器):
157
+ * - authorization_endpoint 必须与 ssoBaseUrl 同源(浏览器跳转目标);
158
+ * - token_endpoint / userinfo_endpoint 必须与 ssoBaseUrl 同源,
159
+ * 或(配置了 serverBaseUrl 时)与内网地址同源。
160
+ * 任一不匹配:告警并返回 null(上层回退到默认端点,fail-safe)。
161
+ * 可通过 config.allowCrossOriginDiscoveryEndpoints 关闭(见配置项警告)。
162
+ */
163
+ private _sanitizeDiscovery;
131
164
  /**
132
165
  * 获取 OIDC Discovery 文档(带缓存 + 超时)
133
166
  *
@@ -249,6 +282,9 @@ declare class SsoClient {
249
282
  * 检查是否已认证(不发起网络请求)
250
283
  *
251
284
  * 仅检查本地是否存在未过期的 access_token。
285
+ * 故意不做 EXPIRY_SKEW_MS 提前量:这是同步的 UI 提示判定(是否显示"已登录"),
286
+ * 提前 10s 翻转 false 会让调用方在 token 仍有效时误显示未登录;真正发请求的
287
+ * getAccessToken/getUserInfo 已带提前量。
252
288
  */
253
289
  isAuthenticated(): boolean;
254
290
  /**
@@ -339,6 +375,12 @@ interface SsoContextValue {
339
375
  refreshUser: () => Promise<void>;
340
376
  /** 获取 access_token(自动刷新过期 token) */
341
377
  getAccessToken: () => Promise<string | null>;
378
+ /**
379
+ * 会话已失效(refresh_token 被撤销/过期),需要用户重新登录。
380
+ * 与 `error` 不同:该标志在 loadUser 拿到"无 token"时不会被清空,
381
+ * 登录成功后才复位,便于子站稳定展示"登录已过期"提示。
382
+ */
383
+ sessionExpired: boolean;
342
384
  /** SsoClient 实例(高级用法) */
343
385
  client: SsoClient;
344
386
  }
@@ -359,8 +401,13 @@ interface SsoProviderProps {
359
401
  * SDK 不会据此自动重试先前失败的 API 请求,重试需由调用方自行实现。
360
402
  */
361
403
  onTokenRefreshed?: (token: string) => void;
404
+ /**
405
+ * 会话失效回调(可选)。refresh_token 被撤销/过期时触发一次,
406
+ * 子站可据此展示"登录已过期,请重新登录"或埋点上报。
407
+ */
408
+ onSessionExpired?: (error: SsoError) => void;
362
409
  }
363
- declare function SsoProvider({ config, children, refreshThreshold, onTokenRefreshed, }: SsoProviderProps): React.FunctionComponentElement<React.ProviderProps<SsoContextValue | null>>;
410
+ declare function SsoProvider({ config, children, refreshThreshold, onTokenRefreshed, onSessionExpired, }: SsoProviderProps): React.FunctionComponentElement<React.ProviderProps<SsoContextValue | null>>;
364
411
  /**
365
412
  * useSso Hook
366
413
  *
@@ -481,6 +528,8 @@ declare function DefaultCallbackError({ error }: {
481
528
  justifyContent: "center";
482
529
  minHeight: string;
483
530
  fontFamily: "system-ui, sans-serif";
531
+ padding: string;
532
+ textAlign: "center";
484
533
  };
485
534
  }, HTMLElement>;
486
535
  declare function CallbackPage({ onSuccess, onError, renderError }?: CallbackPageProps): React.FunctionComponentElement<React.FragmentProps> | React.FunctionComponentElement<{
@@ -58,10 +58,26 @@ interface SsoClientConfig {
58
58
  redirectUri: string;
59
59
  /** SSO 中心地址,如 "https://nihplod.cn" */
60
60
  ssoBaseUrl: string;
61
+ /**
62
+ * 允许 Discovery 文档声明跨源端点(默认 false)。
63
+ *
64
+ * ⚠️ 安全警告:Discovery 文档若被篡改(如中间人/反向代理劫持),攻击者可把
65
+ * token_endpoint 指向自己的服务器窃取 authorization code / refresh_token。
66
+ * SDK 默认校验 authorization_endpoint 必须与 ssoBaseUrl 同源、
67
+ * token_endpoint / userinfo_endpoint 必须与 ssoBaseUrl(或 serverBaseUrl)同源,
68
+ * 不匹配时告警并回退到默认端点。仅当 SSO 中心确实把端点托管在其他域名时
69
+ * 才设置此开关,并自行确保 Discovery 通道可信。
70
+ */
71
+ allowCrossOriginDiscoveryEndpoints?: boolean;
61
72
  /** 请求的 scope(空格分隔),如 "openid profile phone" */
62
73
  scopes?: string;
63
74
  /** RP-Initiated Logout 返回地址(可选)。不传时回退到 redirectUri */
64
75
  postLogoutRedirectUri?: string;
76
+ /**
77
+ * 调试日志开关(默认 false)。开启后输出登录/回调/刷新/登出等关键流程日志,
78
+ * 便于接入方定位问题(生产默认关闭,避免日志噪音)。
79
+ */
80
+ debug?: boolean;
65
81
  /**
66
82
  * 服务端到服务端调用的内网地址(可选,如 http://127.0.0.1:3000)。
67
83
  * 仅用于 discovery / token / userinfo / revocation 等服务器间请求;
@@ -123,11 +139,28 @@ declare class SsoClient {
123
139
  private _discovery;
124
140
  private _discoveryFetchedAt;
125
141
  private _refreshLock;
142
+ /** Discovery 端点 origin 校验失败只告警一次(拒绝的文档不缓存,避免每次调用刷屏) */
143
+ private _discoveryOriginWarned;
126
144
  /** Discovery 文档缓存 TTL(5 分钟) */
127
145
  private static readonly DISCOVERY_TTL_MS;
128
146
  /** Discovery fetch 超时(10 秒) */
129
147
  private static readonly DISCOVERY_TIMEOUT_MS;
130
148
  constructor(config: SsoClientConfig);
149
+ /**
150
+ * 调试日志(config.debug=true 时输出,前缀 [SSO SDK]):
151
+ * 覆盖登录发起 / 回调结果 / 刷新失败 / 登出等关键节点,便于接入方定位问题。
152
+ * 不会输出 token/授权码等敏感值。
153
+ */
154
+ debugLog(...args: unknown[]): void;
155
+ /**
156
+ * 校验 Discovery 文档端点 origin(防文档被篡改后 token/code 被导向攻击者服务器):
157
+ * - authorization_endpoint 必须与 ssoBaseUrl 同源(浏览器跳转目标);
158
+ * - token_endpoint / userinfo_endpoint 必须与 ssoBaseUrl 同源,
159
+ * 或(配置了 serverBaseUrl 时)与内网地址同源。
160
+ * 任一不匹配:告警并返回 null(上层回退到默认端点,fail-safe)。
161
+ * 可通过 config.allowCrossOriginDiscoveryEndpoints 关闭(见配置项警告)。
162
+ */
163
+ private _sanitizeDiscovery;
131
164
  /**
132
165
  * 获取 OIDC Discovery 文档(带缓存 + 超时)
133
166
  *
@@ -249,6 +282,9 @@ declare class SsoClient {
249
282
  * 检查是否已认证(不发起网络请求)
250
283
  *
251
284
  * 仅检查本地是否存在未过期的 access_token。
285
+ * 故意不做 EXPIRY_SKEW_MS 提前量:这是同步的 UI 提示判定(是否显示"已登录"),
286
+ * 提前 10s 翻转 false 会让调用方在 token 仍有效时误显示未登录;真正发请求的
287
+ * getAccessToken/getUserInfo 已带提前量。
252
288
  */
253
289
  isAuthenticated(): boolean;
254
290
  /**
@@ -339,6 +375,12 @@ interface SsoContextValue {
339
375
  refreshUser: () => Promise<void>;
340
376
  /** 获取 access_token(自动刷新过期 token) */
341
377
  getAccessToken: () => Promise<string | null>;
378
+ /**
379
+ * 会话已失效(refresh_token 被撤销/过期),需要用户重新登录。
380
+ * 与 `error` 不同:该标志在 loadUser 拿到"无 token"时不会被清空,
381
+ * 登录成功后才复位,便于子站稳定展示"登录已过期"提示。
382
+ */
383
+ sessionExpired: boolean;
342
384
  /** SsoClient 实例(高级用法) */
343
385
  client: SsoClient;
344
386
  }
@@ -359,8 +401,13 @@ interface SsoProviderProps {
359
401
  * SDK 不会据此自动重试先前失败的 API 请求,重试需由调用方自行实现。
360
402
  */
361
403
  onTokenRefreshed?: (token: string) => void;
404
+ /**
405
+ * 会话失效回调(可选)。refresh_token 被撤销/过期时触发一次,
406
+ * 子站可据此展示"登录已过期,请重新登录"或埋点上报。
407
+ */
408
+ onSessionExpired?: (error: SsoError) => void;
362
409
  }
363
- declare function SsoProvider({ config, children, refreshThreshold, onTokenRefreshed, }: SsoProviderProps): React.FunctionComponentElement<React.ProviderProps<SsoContextValue | null>>;
410
+ declare function SsoProvider({ config, children, refreshThreshold, onTokenRefreshed, onSessionExpired, }: SsoProviderProps): React.FunctionComponentElement<React.ProviderProps<SsoContextValue | null>>;
364
411
  /**
365
412
  * useSso Hook
366
413
  *
@@ -481,6 +528,8 @@ declare function DefaultCallbackError({ error }: {
481
528
  justifyContent: "center";
482
529
  minHeight: string;
483
530
  fontFamily: "system-ui, sans-serif";
531
+ padding: string;
532
+ textAlign: "center";
484
533
  };
485
534
  }, HTMLElement>;
486
535
  declare function CallbackPage({ onSuccess, onError, renderError }?: CallbackPageProps): React.FunctionComponentElement<React.FragmentProps> | React.FunctionComponentElement<{