登录页面与组件样式调整
This commit is contained in:
52
src/actions/auth/login.ts
Normal file
52
src/actions/auth/login.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
'use server'
|
||||
import {cookies} from 'next/headers'
|
||||
import {ApiResponse, call} from '@/lib/api'
|
||||
|
||||
export interface LoginParams {
|
||||
username: string;
|
||||
password: string;
|
||||
remember?: boolean;
|
||||
}
|
||||
|
||||
type LoginResp = {
|
||||
token: string;
|
||||
expires: number;
|
||||
}
|
||||
|
||||
export async function login(props: LoginParams): Promise<ApiResponse> {
|
||||
try {
|
||||
// 尝试登录
|
||||
const result = await call<LoginResp>('/api/auth/login/sms', {
|
||||
username: props.username,
|
||||
password: props.password,
|
||||
remember: props.remember ?? false,
|
||||
})
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
const data = result.data
|
||||
console.log('login', data)
|
||||
|
||||
// 计算过期时间
|
||||
const current = Math.floor(Date.now() / 1000)
|
||||
const future = data.expires - current
|
||||
|
||||
// 保存到 cookies
|
||||
const cookieStore = await cookies()
|
||||
cookieStore.set('auth_token', data.token, {
|
||||
httpOnly: true,
|
||||
sameSite: 'strict',
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
maxAge: Math.max(future, 0),
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: undefined,
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error('请求登陆失败', {cause: e})
|
||||
}
|
||||
}
|
||||
69
src/actions/auth/verify.ts
Normal file
69
src/actions/auth/verify.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
'use server'
|
||||
// 验证验证码函数
|
||||
import {cookies} from 'next/headers'
|
||||
import crypto from 'crypto'
|
||||
import {ApiResponse, call} from '@/lib/api'
|
||||
|
||||
|
||||
export interface VerifyParams {
|
||||
phone: string;
|
||||
captcha: string; // 添加验证码字段
|
||||
}
|
||||
|
||||
export default async function verify(props: VerifyParams): Promise<ApiResponse> {
|
||||
try {
|
||||
// 人机验证
|
||||
if (!props.captcha?.length) {
|
||||
return {
|
||||
success: false,
|
||||
status: 400,
|
||||
message: '请输入验证码',
|
||||
}
|
||||
}
|
||||
const valid = await verifyCaptcha(props.captcha)
|
||||
if (!valid) {
|
||||
return {
|
||||
success: false,
|
||||
status: 400,
|
||||
message: '验证码错误或已过期',
|
||||
}
|
||||
}
|
||||
|
||||
// 请求发送短信
|
||||
return await call('/api/auth/verify/sms', {
|
||||
phone: props.phone,
|
||||
purpose: 0,
|
||||
})
|
||||
}
|
||||
catch (error) {
|
||||
throw new Error('验证码验证失败', {cause: error})
|
||||
}
|
||||
}
|
||||
|
||||
async function verifyCaptcha(userInput: string): Promise<boolean> {
|
||||
const cookieStore = await cookies()
|
||||
const hash = cookieStore.get('captcha_hash')?.value
|
||||
const salt = cookieStore.get('captcha_salt')?.value
|
||||
|
||||
// 如果没有找到验证码cookie,验证失败
|
||||
if (!hash || !salt) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 使用相同的方法哈希用户输入的验证码
|
||||
const userInputHash = crypto
|
||||
.createHmac('sha256', salt)
|
||||
.update(userInput.toLowerCase())
|
||||
.digest('hex')
|
||||
|
||||
// 比较哈希值
|
||||
const isValid = hash === userInputHash
|
||||
|
||||
// 验证后删除验证码cookie,防止重复使用
|
||||
if (isValid) {
|
||||
cookieStore.delete('captcha_hash')
|
||||
cookieStore.delete('captcha_salt')
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
Reference in New Issue
Block a user