All files / src/stores auth.ts

57.14% Statements 8/14
100% Branches 10/10
33.33% Functions 2/6
53.84% Lines 7/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52                                  8x 6x 6x   8x     2x 4x                                               4x    
import { defineStore } from 'pinia'
import { ref } from 'vue'
import type { User } from 'oidc-client-ts'
import {
  userManager,
  signinRedirect,
  handleRedirectCallback,
  signoutRedirect
} from '@/utils/oidc'
 
export interface AuthUser {
  name: string
  phone: string
}
 
/** 导出以便单测:手机号 claim 的兼容逻辑容易被后续改动悄悄破坏 */
export function toAuthUser(u: User | null): AuthUser | null {
  if (!u || u.expired) return null
  const p = u.profile
  const name = p.name ?? p.preferred_username ?? ''
  // Casdoor 的手机号 claim 是 `phone`(非标准 `phone_number`),两者兼容取
  return { name, phone: (p.phone as string | undefined) ?? p.phone_number ?? '' }
}
 
export const useAuthStore = defineStore('auth', () => {
  const user = ref<AuthUser | null>(null)
 
  /** 应用启动时从内存登录态同步到 store。 */
  async function init(): Promise<void> {
    user.value = toAuthUser(await userManager.getUser())
  }
 
  /** 发起 OIDC 登录;当前路径随 state 携带,回调后跳回。 */
  function login(returnPath?: string): Promise<void> {
    return signinRedirect(returnPath)
  }
 
  /** 处理授权码回调,装载登录态,返回登录前路径。 */
  async function handleCallback(): Promise<string> {
    const returnPath = await handleRedirectCallback()
    user.value = toAuthUser(await userManager.getUser())
    return returnPath
  }
 
  /** 登出:跳转 IdP 结束 SSO 会话,回 /logged-out。 */
  function logout(): Promise<void> {
    return signoutRedirect()
  }
 
  return { user, init, login, handleCallback, logout }
})