oauthHashRestore.js 2.04 KB
/**
 * @description 从 OAuth 回跳 URL 中恢复 hash 路由。
 * 某些回跳链路只会稳定保留 base URL,因此需要借助 ret_hash 在前端复原原始 hash。
 * @param {string} href 当前完整地址
 * @returns {string|null} 需要替换的新地址;无需处理时返回 null
 */
export const getOAuthRestoredUrl = href => {
  if (!href || typeof href !== 'string') return null

  let url = null
  try {
    url = new URL(href)
  } catch (error) {
    return null
  }

  const ret_hash = url.searchParams.get('ret_hash')
  if (!ret_hash || url.hash) return null

  url.searchParams.delete('ret_hash')
  const base = url.toString().split('#')[0]
  return `${base}${ret_hash}`
}

/**
 * @description 构造微信 OAuth 授权地址,显式拆分 base_url 与 hash。
 * @param {string} target_href 授权前的目标地址
 * @param {{ is_dev?: boolean, test_openid?: string }} [options] 额外选项
 * @returns {string|null} 可直接跳转的授权地址;输入非法时返回 null
 */
export const buildOAuthAuthorizeUrl = (target_href, options = {}) => {
  if (!target_href || typeof target_href !== 'string') return null

  const [base_part, ...hash_parts] = target_href.split('#')
  if (!base_part) return null

  const ret_hash = hash_parts.length ? `#${hash_parts.join('#')}` : ''
  const base_url = encodeURIComponent(base_part)
  const encoded_hash = encodeURIComponent(ret_hash)

  let short_url = `/srv/?f=behalo&a=openid&res=${base_url}&ret_hash=${encoded_hash}`
  if (options.is_dev && options.test_openid) {
    short_url += `&test_openid=${encodeURIComponent(options.test_openid)}`
  }

  return short_url
}

/**
 * @description 在应用初始化前尝试恢复 OAuth 回跳丢失的 hash。
 * @returns {boolean} 是否发生了地址恢复
 */
export const restoreHashAfterOAuth = () => {
  if (typeof window === 'undefined' || typeof window.location === 'undefined') {
    return false
  }

  const next_url = getOAuthRestoredUrl(window.location.href)
  if (!next_url) return false

  window.history.replaceState(null, '', next_url)
  return true
}