init
This commit is contained in:
205
src/services/authService.ts
Normal file
205
src/services/authService.ts
Normal file
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* Authentication Service - Handles user authentication operations
|
||||
* Feature: api-interface-optimization
|
||||
* Validates: Requirements 12, 13
|
||||
*/
|
||||
|
||||
import api from './api';
|
||||
|
||||
// Token storage keys
|
||||
const ACCESS_TOKEN_KEY = 'access_token';
|
||||
const REFRESH_TOKEN_KEY = 'refresh_token';
|
||||
|
||||
// Types
|
||||
export interface User {
|
||||
id: number;
|
||||
email: string;
|
||||
username: string;
|
||||
avatar?: string;
|
||||
is_active: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface TokenPair {
|
||||
access_token: string;
|
||||
refresh_token: string;
|
||||
expires_in: number;
|
||||
}
|
||||
|
||||
export interface RegisterInput {
|
||||
email: string;
|
||||
password: string;
|
||||
username: string;
|
||||
}
|
||||
|
||||
export interface LoginInput {
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface AuthResponse {
|
||||
success: boolean;
|
||||
data: {
|
||||
user: User;
|
||||
tokens: TokenPair;
|
||||
};
|
||||
}
|
||||
|
||||
export interface RefreshResponse {
|
||||
success: boolean;
|
||||
data: TokenPair;
|
||||
}
|
||||
|
||||
// Token management
|
||||
export function getAccessToken(): string | null {
|
||||
return localStorage.getItem(ACCESS_TOKEN_KEY);
|
||||
}
|
||||
|
||||
export function getRefreshToken(): string | null {
|
||||
return localStorage.getItem(REFRESH_TOKEN_KEY);
|
||||
}
|
||||
|
||||
export function setTokens(tokens: TokenPair): void {
|
||||
localStorage.setItem(ACCESS_TOKEN_KEY, tokens.access_token);
|
||||
localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refresh_token);
|
||||
}
|
||||
|
||||
export function clearTokens(): void {
|
||||
localStorage.removeItem(ACCESS_TOKEN_KEY);
|
||||
localStorage.removeItem(REFRESH_TOKEN_KEY);
|
||||
}
|
||||
|
||||
export function isAuthenticated(): boolean {
|
||||
return !!getAccessToken();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register a new user
|
||||
* Validates: Requirements 12.1, 12.2
|
||||
*/
|
||||
export async function register(input: RegisterInput): Promise<{ user: User; tokens: TokenPair }> {
|
||||
const response = await api.post<AuthResponse>('/auth/register', input);
|
||||
if (response.success && response.data) {
|
||||
setTokens(response.data.tokens);
|
||||
return response.data;
|
||||
}
|
||||
throw new Error('Registration failed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Login with email and password
|
||||
* Validates: Requirements 12.2
|
||||
*/
|
||||
export async function login(input: LoginInput): Promise<{ user: User; tokens: TokenPair }> {
|
||||
const response = await api.post<AuthResponse>('/auth/login', input);
|
||||
if (response.success && response.data) {
|
||||
setTokens(response.data.tokens);
|
||||
return response.data;
|
||||
}
|
||||
throw new Error('Login failed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh access token using refresh token
|
||||
* Validates: Requirements 12.4
|
||||
*/
|
||||
export async function refreshAccessToken(): Promise<TokenPair> {
|
||||
const refreshToken = getRefreshToken();
|
||||
if (!refreshToken) {
|
||||
throw new Error('No refresh token available');
|
||||
}
|
||||
|
||||
const response = await api.post<RefreshResponse>('/auth/refresh', {
|
||||
refresh_token: refreshToken,
|
||||
});
|
||||
|
||||
if (response.success && response.data) {
|
||||
setTokens(response.data);
|
||||
return response.data;
|
||||
}
|
||||
throw new Error('Token refresh failed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout - clear tokens
|
||||
*/
|
||||
export function logout(): void {
|
||||
clearTokens();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get GitHub OAuth login URL
|
||||
* Validates: Requirements 13.1
|
||||
*/
|
||||
export function getGitHubLoginUrl(state?: string): string {
|
||||
const baseUrl = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8080/api/v1';
|
||||
const url = new URL(`${baseUrl}/auth/github`);
|
||||
if (state) {
|
||||
url.searchParams.append('state', state);
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to GitHub OAuth login
|
||||
* Validates: Requirements 13.1
|
||||
*/
|
||||
export function loginWithGitHub(state?: string): void {
|
||||
window.location.href = getGitHubLoginUrl(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle GitHub OAuth callback
|
||||
* Validates: Requirements 13.4, 13.5
|
||||
*/
|
||||
export async function handleGitHubCallback(code: string): Promise<{ user: User; tokens: TokenPair }> {
|
||||
const response = await api.get<AuthResponse>('/auth/github/callback', { code });
|
||||
if (response.success && response.data) {
|
||||
setTokens(response.data.tokens);
|
||||
return response.data;
|
||||
}
|
||||
throw new Error('GitHub authentication failed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current user information
|
||||
*/
|
||||
export async function getCurrentUser(): Promise<User> {
|
||||
const response = await api.get<{ success: boolean; data: User }>('/auth/me');
|
||||
if (response.success && response.data) {
|
||||
return response.data;
|
||||
}
|
||||
throw new Error('Failed to get user information');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user password
|
||||
*/
|
||||
export async function updatePassword(oldPassword: string, newPassword: string): Promise<void> {
|
||||
const response = await api.post<{ success: boolean }>('/auth/password', {
|
||||
old_password: oldPassword,
|
||||
new_password: newPassword,
|
||||
});
|
||||
if (!response.success) {
|
||||
throw new Error('Failed to update password');
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
register,
|
||||
login,
|
||||
logout,
|
||||
refreshAccessToken,
|
||||
getAccessToken,
|
||||
getRefreshToken,
|
||||
setTokens,
|
||||
clearTokens,
|
||||
isAuthenticated,
|
||||
loginWithGitHub,
|
||||
getGitHubLoginUrl,
|
||||
handleGitHubCallback,
|
||||
getCurrentUser,
|
||||
updatePassword,
|
||||
};
|
||||
Reference in New Issue
Block a user