| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- "use client"
- import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react'
- import { authApi } from './api'
- interface User {
- id: string
- username: string
- email?: string
- role: 'admin' | 'user'
- createdAt: string
- lastLogin?: string
- }
- interface AuthState {
- user: User | null
- token: string | null
- isAuthenticated: boolean
- isLoading: boolean
- error: string | null
- }
- interface AuthContextType extends AuthState {
- login: (username: string, password?: string) => Promise<void>
- logout: () => void
- refreshToken: () => Promise<void>
- clearError: () => void
- authMethod: 'none' | 'unix' | 'jwt'
- authEnabled: boolean
- }
- const AuthContext = createContext<AuthContextType | undefined>(undefined)
- export function AuthProvider({ children }: { children: ReactNode }) {
- const [state, setState] = useState<AuthState>({
- user: null,
- token: null,
- isAuthenticated: false,
- isLoading: true,
- error: null
- })
- // Get authentication method from server config
- const authMethod = typeof window !== 'undefined' && window.__SERVER_CONFIG__
- ? window.__SERVER_CONFIG__.authMethod
- : 'jwt';
- const authEnabled = typeof window !== 'undefined' && window.__SERVER_CONFIG__
- ? window.__SERVER_CONFIG__.authEnabled
- : false;
- useEffect(() => {
- // Check for existing authentication on mount
- if (authMethod === 'unix') {
- // For Unix auth, check for unix_user in localStorage
- const unixUser = localStorage.getItem('unix_user')
- if (unixUser) {
- validateUnixUser(unixUser)
- } else {
- setState(prev => ({ ...prev, isLoading: false }))
- }
- } else {
- // For JWT auth, check for token in localStorage
- const token = localStorage.getItem('auth_token')
- if (token) {
- validateToken(token)
- } else {
- setState(prev => ({ ...prev, isLoading: false }))
- }
- }
- }, [authMethod])
- const validateToken = async (token: string) => {
- try {
- const data = await authApi.validateToken(token)
- setState({
- user: data.user,
- token,
- isAuthenticated: true,
- isLoading: false,
- error: null
- })
- localStorage.setItem('auth_token', token)
- } catch (error) {
- console.error('Token validation error:', error)
- localStorage.removeItem('auth_token')
- setState({
- user: null,
- token: null,
- isAuthenticated: false,
- isLoading: false,
- error: 'Session expired. Please log in again.'
- })
- }
- }
- const validateUnixUser = async (unixUser: string) => {
- try {
- // For Unix auth, we need to validate by attempting to get current user
- const data = await authApi.getCurrentUser()
- setState({
- user: data.user,
- token: `unix_${unixUser}`, // Store a pseudo-token for consistency
- isAuthenticated: true,
- isLoading: false,
- error: null
- })
- localStorage.setItem('unix_user', unixUser)
- localStorage.setItem('auth_token', `unix_${unixUser}`) // Store pseudo-token for API calls
- } catch (error) {
- console.error('Unix user validation error:', error)
- localStorage.removeItem('unix_user')
- localStorage.removeItem('auth_token')
- setState({
- user: null,
- token: null,
- isAuthenticated: false,
- isLoading: false,
- error: 'Session expired. Please log in again.'
- })
- }
- }
- const login = async (username: string, password?: string) => {
- setState(prev => ({ ...prev, isLoading: true, error: null }))
- try {
- const data = await authApi.login(username, password)
- const { token, user } = data
- setState({
- user,
- token,
- isAuthenticated: true,
- isLoading: false,
- error: null
- })
- if (authMethod === 'unix') {
- localStorage.setItem('unix_user', username)
- localStorage.setItem('auth_token', token) // Store token for API calls
- } else {
- localStorage.setItem('auth_token', token)
- }
- } catch (error) {
- setState(prev => ({
- ...prev,
- isLoading: false,
- error: error instanceof Error ? error.message : 'Login failed'
- }))
- }
- }
- const logout = () => {
- if (authMethod === 'unix') {
- localStorage.removeItem('unix_user')
- }
- localStorage.removeItem('auth_token')
- setState({
- user: null,
- token: null,
- isAuthenticated: false,
- isLoading: false,
- error: null
- })
- }
- const refreshToken = async () => {
- const { token } = state
- if (!token) return
- try {
- const data = await authApi.refreshToken()
- const newToken = data.token
- setState(prev => ({ ...prev, token: newToken }))
- localStorage.setItem('auth_token', newToken)
- } catch (error) {
- console.error('Token refresh error:', error)
- logout()
- }
- }
- const clearError = () => {
- setState(prev => ({ ...prev, error: null }))
- }
- const value: AuthContextType = {
- ...state,
- login,
- logout,
- refreshToken,
- clearError,
- authMethod,
- authEnabled
- }
- return (
- <AuthContext.Provider value={value}>
- {children}
- </AuthContext.Provider>
- )
- }
- export function useAuth(): AuthContextType {
- const context = useContext(AuthContext)
- if (context === undefined) {
- throw new Error('useAuth must be used within an AuthProvider')
- }
- return context
- }
|