更新移动端认证API,新增地理位置参数支持,优化登录逻辑以处理位置获取失败的情况,提升用户体验和代码可维护性。
This commit is contained in:
@@ -40,7 +40,7 @@ interface AuthResponse {
|
|||||||
|
|
||||||
// 定义Auth API接口类型
|
// 定义Auth API接口类型
|
||||||
interface AuthAPIType {
|
interface AuthAPIType {
|
||||||
login: (username: string, password: string) => Promise<AuthLoginResponse>;
|
login: (username: string, password: string, latitude?: number, longitude?: number) => Promise<AuthLoginResponse>;
|
||||||
register: (username: string, email: string, password: string) => Promise<AuthResponse>;
|
register: (username: string, email: string, password: string) => Promise<AuthResponse>;
|
||||||
logout: () => Promise<AuthResponse>;
|
logout: () => Promise<AuthResponse>;
|
||||||
getCurrentUser: () => Promise<User>;
|
getCurrentUser: () => Promise<User>;
|
||||||
@@ -54,9 +54,14 @@ interface AuthAPIType {
|
|||||||
// Auth相关API
|
// Auth相关API
|
||||||
export const AuthAPI: AuthAPIType = {
|
export const AuthAPI: AuthAPIType = {
|
||||||
// 登录API
|
// 登录API
|
||||||
login: async (username: string, password: string) => {
|
login: async (username: string, password: string, latitude?: number, longitude?: number) => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(`${API_BASE_URL}/auth/login`, { username, password });
|
const response = await axios.post(`${API_BASE_URL}/auth/login`, {
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
latitude,
|
||||||
|
longitude
|
||||||
|
});
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
@@ -63,9 +63,9 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
|||||||
|
|
||||||
|
|
||||||
// 登录函数
|
// 登录函数
|
||||||
const login = async (username: string, password: string) => {
|
const login = async (username: string, password: string, latitude?: number, longitude?: number) => {
|
||||||
try {
|
try {
|
||||||
const response = await AuthAPI.login(username, password);
|
const response = await AuthAPI.login(username, password, latitude, longitude);
|
||||||
const { token, user } = response;
|
const { token, user } = response;
|
||||||
|
|
||||||
// 保存到状态和本地存储
|
// 保存到状态和本地存储
|
||||||
|
|||||||
@@ -25,10 +25,37 @@ const LoginPage: React.FC = () => {
|
|||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await login(username, password);
|
// 获取地理位置
|
||||||
|
const position = await new Promise<GeolocationPosition>((resolve, reject) => {
|
||||||
|
if (!navigator.geolocation) {
|
||||||
|
reject(new Error('浏览器不支持地理位置功能'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigator.geolocation.getCurrentPosition(
|
||||||
|
resolve,
|
||||||
|
(err) => reject(new Error(`获取位置失败: ${err.message}`)),
|
||||||
|
{ timeout: 5000 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const { latitude, longitude } = position.coords;
|
||||||
|
await login(username, password, latitude, longitude);
|
||||||
navigate('/');
|
navigate('/');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(handleApiError(err));
|
// 如果获取位置失败,仍然允许登录但不带位置信息
|
||||||
|
const error = err instanceof Error ? err : new Error(String(err));
|
||||||
|
if (error.message.includes('获取位置失败')) {
|
||||||
|
console.warn('获取位置失败:', err);
|
||||||
|
try {
|
||||||
|
await login(username, password);
|
||||||
|
navigate('/');
|
||||||
|
} catch (loginErr) {
|
||||||
|
setError(handleApiError(loginErr));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setError(handleApiError(err));
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export interface MenuItem {
|
|||||||
export interface AuthContextType {
|
export interface AuthContextType {
|
||||||
user: User | null;
|
user: User | null;
|
||||||
token: string | null;
|
token: string | null;
|
||||||
login: (username: string, password: string) => Promise<void>;
|
login: (username: string, password: string, latitude?: number, longitude?: number) => Promise<void>;
|
||||||
logout: () => Promise<void>;
|
logout: () => Promise<void>;
|
||||||
isAuthenticated: boolean;
|
isAuthenticated: boolean;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export function createAuthRoutes(withAuth: WithAuth) {
|
|||||||
authRoutes.post('/login', async (c) => {
|
authRoutes.post('/login', async (c) => {
|
||||||
try {
|
try {
|
||||||
const auth = c.get('auth')
|
const auth = c.get('auth')
|
||||||
const { username, password } = await c.req.json()
|
const { username, password, latitude, longitude } = await c.req.json()
|
||||||
|
|
||||||
if (!username || !password) {
|
if (!username || !password) {
|
||||||
return c.json({ error: '用户名和密码不能为空' }, 400)
|
return c.json({ error: '用户名和密码不能为空' }, 400)
|
||||||
@@ -69,7 +69,9 @@ export function createAuthRoutes(withAuth: WithAuth) {
|
|||||||
user_id: result.user.id,
|
user_id: result.user.id,
|
||||||
login_time: apiClient.database.fn.now(),
|
login_time: apiClient.database.fn.now(),
|
||||||
ip_address: c.req.header('x-forwarded-for') || '未知',
|
ip_address: c.req.header('x-forwarded-for') || '未知',
|
||||||
user_agent: c.req.header('user-agent') || '未知'
|
user_agent: c.req.header('user-agent') || '未知',
|
||||||
|
latitude: latitude || null,
|
||||||
|
longitude: longitude || null
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user