'use server' import {cookies} from 'next/headers' import {ApiResponse, UnauthorizedError} from '@/lib/api' import {User} from '@/lib/models' import {callByDevice, callByUser} from '@/actions/base' type TokenResp = { access_token: string refresh_token: string expires_in: number token_type: string scope?: string } export async function login(props: { username: string password: string remember: boolean mode: 'phone_code' | 'password' }): Promise { // 尝试登录 const result = await callByDevice('/api/auth/token', { ...props, grant_type: 'password', login_type: props.mode, }) if (!result.success) { return result } // 保存到 cookies const data = result.data const cookieStore = await cookies() cookieStore.set('auth_token', data.access_token, { httpOnly: true, sameSite: 'strict', maxAge: Math.max(data.expires_in, 0), }) cookieStore.set('auth_refresh', data.refresh_token, { httpOnly: true, sameSite: 'strict', maxAge: Number.MAX_SAFE_INTEGER, }) return { success: true, data: undefined, } } export async function logout() { const cookieStore = await cookies() // 尝试删除后台会话 const access_token = cookieStore.get('auth_token')?.value const refresh_token = cookieStore.get('auth_refresh')?.value if (access_token && refresh_token) { await callByUser('/api/auth/revoke', { access_token, refresh_token, }) } // 删除 cookies cookieStore.set('auth_token', '', { httpOnly: true, sameSite: 'strict', maxAge: -1, }) cookieStore.set('auth_refresh', '', { httpOnly: true, sameSite: 'strict', maxAge: -1, }) return { success: true, data: undefined, } } export async function getProfile() { return await callByUser('/api/auth/introspect') } export async function refreshAuth() { const cookie = await cookies() const userRefresh = cookie.get('auth_refresh')?.value if (!userRefresh) { throw UnauthorizedError } // 请求刷新访问令牌 const resp = await callByDevice(`/api/auth/token`, { grant_type: 'refresh_token', refresh_token: userRefresh, }) // 处理请求 if (!resp.success) { if (resp.status === 401) { cookie.delete('auth_refresh') } throw UnauthorizedError } // 解析响应 const data = resp.data const nextAccessToken = data.access_token const nextRefreshToken = data.refresh_token const expiresIn = data.expires_in // 保存令牌到 cookies cookie.set('auth_token', nextAccessToken, { httpOnly: true, sameSite: 'strict', maxAge: Math.max(expiresIn, 0), }) cookie.set('auth_refresh', nextRefreshToken, { httpOnly: true, sameSite: 'strict', maxAge: Number.MAX_SAFE_INTEGER, }) // 返回新的访问令牌 return { access_token: nextAccessToken, refresh_token: nextRefreshToken, } }