Skip to content

useAuth

简化 App 登录注册等授权操作。

Type Declarations

本系列方法用到的一些公共类型。

ts
interface RequestResult {
  isOk: boolean
  msg: string
}

/**
 * 登录结果
 * @description 失败的话没有登录数据,会返回 `null`
 */
interface LoginResult extends RequestResult {
  data: null | LoginInfo
}

tokenType

完整的 Token 需要包含 Token Type 作为开头,我们业务的 Token Type 固定为 Bearer

  • Supported Platforms:
Browser
Electron
App
Server
Scriptlet
  • Type Declarations:
ts
type TokenType = 'Bearer'
  • Example:
ts
import { useAuth } from '@lunarxyz/core'

const { tokenType } = useAuth()
console.log(tokenType) // 'Bearer'

loginInfo

登录信息。

TIP

这里并不是直接导出一个响应式对象,而是通过 toRefs 导出了 Ref 变量,请见下方的 Example 。

  • Supported Platforms:
Browser
Electron
App
Server
Scriptlet
  • Type Declarations:
ts
/**
 * 登录信息,最终导出的是多个 Vue Ref 变量
 */
interface LoginInfo {
  /**
   * 用户 ID
   */
  userId: string

  /**
   * 用户名
   */
  username: string

  /**
   * 手机号码
   */
  phoneNumber: string

  /**
   * 是否已设置密码
   */
  hasPassword: boolean

  /**
   * 已包含凭证头的完整用户凭证
   */
  token: Token

  /**
   * 用来刷新用户凭证有效期的凭证
   */
  refreshToken: string

  /**
   * 几秒后过期
   */
  expiresIn: number

  /**
   * 过期时间( 13 位时间戳)
   */
  expiresIime: number
}

/**
 * 用户凭证要么为空,要么是以 tokenType 开头
 */
type Token<T extends string> = `${TokenType} ${T}` | ''
  • Example:
ts
import { useAuth } from '@lunarxyz/core'

// 这里拿到的都是 Ref 响应式变量,必须用 `.value` 才能拿到正确的值
const { token, phoneNumber } = useAuth()
console.log({
  token: token.value,
  phoneNumber: phoneNumber.value,
})
// {
//   "token": "Bearer 58f7*********************bc36",
//   "phoneNumber": "13800138000"
// }

autoLogin

自动登录,会自动执行 getToken -> login -> register 等一系列流程。

如果其中有一个流程成功,则提前返回登录信息。

如果三个流程都失败,则返回空的登录信息,可以通过 isOk 来判断是否成功。

  • Supported Platforms:
Browser
Electron
App
Server
Scriptlet
  • Type Declarations:
ts
/**
 * 自动登录
 */
declare function autoLogin(options: AutoLoginOptions): Promise<LoginResult>

/**
 * 自动登录选项
 */
interface AutoLoginOptions {
  /**
   * 手机号码
   */
  phoneNumber: string

  /**
   * 登录验证码
   */
  code: string

  /**
   * 是否跳过登录
   * @description 如果知道手机号未注册,可以传 `true` 直接走注册流程
   * @default false
   */
  skipLogin?: boolean

  /**
   * 是否查询 Token
   * @description 传 `true` 会先查一次 Token ,传 `false` 直接登录
   * @default true
   */
  queryToken?: boolean

  /**
   * 是否查询用户详情
   * @description 会传递给 `getToken` ,详见该 API 的说明
   */
  queryInfo?: boolean

  /**
   * 父级 ID
   * @description 会传递给 `register` ,详见该 API 的说明
   */
  parentId?: string
}
  • Example:
ts
import { ref } from 'vue'
import { useAuth, useSMS } from '@lunarxyz/core'

async function run() {
  /**
   * 需要先发送登录短信
   * @description 实际业务请让用户手动触发,在手机上查收短信
   */
  const phoneNumber = ref<string>('13800138000')
  const { sendCode } = useSMS()
  const { msg: loginCodeMsg } = await sendCode('login', phoneNumber.value)
  if (loginCodeMsg.includes('未注册')) {
    await sendCode('register', phoneNumber.value)
  }

  /**
   * 再执行自动登录并获取登录信息
   * @description 这里的验证码需要让用户输入后才拿到
   */
  const { autoLogin } = useAuth()
  const { isOk, msg, data } = await autoLogin({
    phoneNumber: phoneNumber.value,
    code: '123456',
    queryToken: true,
    parentId: '88',
  })
  console.log({ isOk, msg, data })
  // {
  //   "isOk": true,
  //   "msg": "",
  //   "data": {
  //     "userId": "123",
  //     "username": "13800138000",
  //     "phoneNumber": "13800138000",
  //     "hasPassword": false,
  //     "token": "Bearer f3e7*********************0ce9",
  //     "refreshToken": "",
  //     "expiresIn": 0,
  //     "expiresIime": 0
  //   }
  // }
}
run().catch((e) => {
  console.log(e)
})

getToken

获取有效期内的 Token 。

TIP

获取 Token 之前,必须发送一次验证码才可以,该方法走 登录流程 获取验证码。

WARNING

如果通过该方法拿到 Token ,会请求用户详情刷新部分用户信息(但不包括 expiresInexpiresIimehasPasswordrefreshToken 这 4 个数据,所以该方法仅建议在不需要这 4 个数据的活动页面使用,如果需要这 4 个数据,请直接走登录流程。

  • Supported Platforms:
Browser
Electron
App
Server
Scriptlet
  • Type Declarations:
ts
/**
 * 获取有效期内的 Token
 */
declare function getToken(options: GetTokenOptions): Promise<LoginResult>

/**
 * 获取 Token 选项
 */
interface GetTokenOptions {
  /**
   * 手机号码
   */
  phoneNumber: string

  /**
   * 登录验证码
   */
  code: string

  /**
   * 是否查询用户详情
   * @description 默认会查询一次 memberinfo ,传 `false` 则不查,可以另外手动请求
   * @default true
   */
  queryInfo?: boolean
}
  • Example:
ts
import { ref } from 'vue'
import { useAuth, useSMS } from '@lunarxyz/core'

async function run() {
  /**
   * 需要先发送登录短信
   * @description 实际业务请让用户手动触发,在手机上查收短信
   */
  const phoneNumber = ref<string>('13800138000')
  const { sendCode } = useSMS()
  await sendCode('login', phoneNumber.value)

  /**
   * 再执行获取 Token 以及登录信息
   * @description 这里的验证码需要让用户输入后才拿到
   */
  const { getToken } = useAuth()
  const { isOk, msg, data } = await getToken({
    phoneNumber: phoneNumber.value,
    code: '123456',
    queryInfo: false,
  })
  console.log({ isOk, msg, data })
  // {
  //   "isOk": true,
  //   "msg": "",
  //   "data": {
  //     "userId": "123",
  //     "username": "13800138000",
  //     "phoneNumber": "13800138000",
  //     "hasPassword": false,
  //     "token": "Bearer f3e7*********************0ce9",
  //     "refreshToken": "",
  //     "expiresIn": 0,
  //     "expiresIime": 0
  //   }
  // }
}
run().catch((e) => {
  console.log(e)
})

login

App 登录,支持验证码登录和账号密码登录。

TIP

执行登录之前,必须发送一次登录验证码才可以。

登录成功后,接口响应回来的数据会自动更新给响应式的 loginInfo ,并更新本地存储。

  • Supported Platforms:
Browser
Electron
App
Server
Scriptlet
  • Type Declarations:
ts
/**
 * 登录
 */
declare function login(options: LoginOptions): Promise<LoginResult>

/**
 * 登录选项
 */
interface LoginOptions {
  /**
   * 登录类型,目前只支持验证码和密码登录
   */
  type: 'code' | 'password'

  /**
   * 手机号码
   */
  phoneNumber: string

  /**
   * 验证码, `type` 为 `code` 时必传
   */
  code?: string

  /**
   * 登录密码, `type` 为 `password` 时必传
   */
  password?: string
}
  • Example:
ts
import { ref } from 'vue'
import { useAuth, useSMS } from '@lunarxyz/core'

async function run() {
  /**
   * 需要先发送登录短信
   * @description 实际业务请让用户手动触发,在手机上查收短信
   */
  const phoneNumber = ref<string>('13800138000')
  const { sendCode } = useSMS()
  await sendCode('login', phoneNumber.value)

  /**
   * 再执行登录并获取登录信息
   * @description 这里的验证码需要让用户输入后才拿到
   */
  const { login } = useAuth()
  const { isOk, msg, data } = await login({
    type: 'code',
    phoneNumber: phoneNumber.value,
    code: '123456',
  })
  console.log({ isOk, msg, data })
  // {
  //   "isOk": true,
  //   "msg": "",
  //   "data": {
  //     "userId": "123",
  //     "username": "13800138000",
  //     "phoneNumber": "13800138000",
  //     "hasPassword": true,
  //     "token": "Bearer f3e7*********************0ce9",
  //     "refreshToken": "a5a8f144-6806-474c-bd7c-7cb7ca550b9f",
  //     "expiresIn": 43199,
  //     "expiresIime": 1658695221652
  //   }
  // }
}
run().catch((e) => {
  console.log(e)
})

register

App 注册,注册成功后会返回登录信息。

TIP

执行注册之前,必须发送一次注册验证码才可以。

注册成功后,接口响应回来的数据会自动更新给响应式的 loginInfo ,并更新本地存储。

  • Supported Platforms:
Browser
Electron
App
Server
Scriptlet
  • Type Declarations:
ts
/**
 * 注册
 */
declare function register(options: RegisterOptions): Promise<LoginResult>

/**
 * 注册选项
 */
interface RegisterOptions {
  /**
   * 手机号码
   */
  phoneNumber: string

  /**
   * 验证码
   */
  code: string

  /**
   * 密码
   */
  password?: string

  /**
   * 二次确认密码
   */
  confirmPassword?: string

  /**
   * 父级 ID
   * @description 如果有拉新需求,这里传入邀请人的用户 ID
   */
  parentId?: string
}
  • Example:
ts
import { ref } from 'vue'
import { useAuth, useSMS } from '@lunarxyz/core'

async function run() {
  /**
   * 需要先发送注册短信
   * @description 实际业务请让用户手动触发,在手机上查收短信
   */
  const phoneNumber = ref<string>('13800138000')
  const { sendCode } = useSMS()
  await sendCode('register', phoneNumber.value)

  /**
   * 再执行注册并获取登录信息
   * @description 这里的验证码需要让用户输入后才拿到
   */
  const { register } = useAuth()
  const { isOk, msg, data } = await register({
    phoneNumber: phoneNumber.value,
    code: '123456',
    password: '11111111',
    confirmPassword: '11111111',
  })
  console.log({ isOk, msg, data })
  // {
  //   "isOk": true,
  //   "msg": "",
  //   "data": {
  //     "userId": "123",
  //     "username": "13800138000",
  //     "phoneNumber": "13800138000",
  //     "hasPassword": true,
  //     "token": "Bearer f3e7*********************0ce9",
  //     "refreshToken": "a5a8f144-6806-474c-bd7c-7cb7ca550b9f",
  //     "expiresIn": 43199,
  //     "expiresIime": 1658695221652
  //   }
  // }
}
run().catch((e) => {
  console.log(e)
})

saveLoginInfo

保存登录信息,用于登录或者注册后,把接口响应回来的数据更新给响应式的 loginInfo ,并更新本地的 Storage 信息。

WARNING

一般情况下无需手动调用,在登录、注册等环节会自动执行。

导出该方法只是为了给需要手动处理的特殊情况使用。

  • Supported Platforms:
Browser
Electron
App
Server
Scriptlet
  • Type Declarations:
ts
declare function saveLoginInfo(
  /**
   * 登录成功后接口返回的登录信息
   */
  res: any
): LoginInfo

restoreLoginInfo

回显登录信息,可以从本地存储恢复登录信息,避免每次刷新页面就失去登录状态。

TIP

建议在入口文件( App.vue / main.ts)调用,比其他接口请求先执行。

  • Supported Platforms:
Browser
Electron
App
Server
Scriptlet
  • Type Declarations:
ts
declare function restoreLoginInfo(): void
  • Example:
ts
import { useAuth } from '@lunarxyz/core'

const { restoreLoginInfo } = useAuth()
restoreLoginInfo()

isTokenExpired

判断 Token 是否已过期,会调用一次用户详情接口来判断 Token 是否真的无效,所以它是一个异步函数。

之所以这样做,是因为 expiresIime 可能不准确,例如顶号等行为会让 Token 提前失效。

  • Supported Platforms:
Browser
Electron
App
Server
Scriptlet
  • Type Declarations:
ts
declare function isTokenExpired(): Promise<boolean>
  • Example:
ts
import { useAuth } from '@lunarxyz/core'

async function run() {
  const { isTokenExpired } = useAuth()
  const isExpired = await isTokenExpired()
  if (isExpired) {
    console.log('Token 失效')
    // 操作一些引导登录的行为
  }
}
run().catch((e) => {
  console.log(e)
})

Released under the MIT License.