diff --git a/furumi-node-player/README.md b/furumi-node-player/README.md index d90ac79..69863f2 100644 --- a/furumi-node-player/README.md +++ b/furumi-node-player/README.md @@ -8,6 +8,7 @@ ## Запуск 1. Скопируй `server/.env.example` в `server/.env` и заполни OIDC параметры. + - Если нужно запустить без авторизации, поставь `DISABLE_AUTH=true` (OIDC параметры тогда не требуются). 2. В одном терминале: - `cd server` - `npm run dev` diff --git a/furumi-node-player/client/src/App.css b/furumi-node-player/client/src/App.css index e1c66fc..1334e57 100644 --- a/furumi-node-player/client/src/App.css +++ b/furumi-node-player/client/src/App.css @@ -20,6 +20,32 @@ color: #5a6475; } +.settings { + margin-bottom: 16px; + padding: 12px; + border: 1px solid #e6eaf2; + border-radius: 10px; + background: #f8fafc; +} + +.toggle { + display: flex; + align-items: center; + gap: 10px; + color: #0f172a; + font-weight: 600; +} + +.toggle input { + width: 18px; + height: 18px; +} + +.hint { + margin: 10px 0 0; + color: #5a6475; +} + .btn { display: inline-block; text-decoration: none; diff --git a/furumi-node-player/client/src/App.tsx b/furumi-node-player/client/src/App.tsx index d2a6ac7..cb90f52 100644 --- a/furumi-node-player/client/src/App.tsx +++ b/furumi-node-player/client/src/App.tsx @@ -7,14 +7,30 @@ type UserProfile = { email?: string } +const NO_AUTH_STORAGE_KEY = 'furumiNodePlayer.runWithoutAuth' + function App() { const [loading, setLoading] = useState(true) const [user, setUser] = useState(null) const [error, setError] = useState(null) + const [runWithoutAuth, setRunWithoutAuth] = useState(() => { + try { + return window.localStorage.getItem(NO_AUTH_STORAGE_KEY) === '1' + } catch { + return false + } + }) const apiBase = useMemo(() => import.meta.env.VITE_API_BASE_URL ?? '', []) useEffect(() => { + if (runWithoutAuth) { + setError(null) + setUser({ sub: 'noauth', name: 'No Auth' }) + setLoading(false) + return + } + const loadMe = async () => { try { const response = await fetch(`${apiBase}/api/me`, { @@ -40,7 +56,7 @@ function App() { } void loadMe() - }, [apiBase]) + }, [apiBase, runWithoutAuth]) const loginUrl = `${apiBase}/api/login` const logoutUrl = `${apiBase}/api/logout` @@ -51,9 +67,37 @@ function App() {

OIDC Login

Авторизация обрабатывается на Express сервере.

+
+ +
+ {loading &&

Проверяю сессию...

} {error &&

Ошибка: {error}

} + {!loading && runWithoutAuth && ( +

+ Режим без авторизации включён. Для входа отключи настройку выше. +

+ )} + {!loading && !user && ( Войти через OIDC @@ -75,9 +119,11 @@ function App() { Email: {user.email}

)} -
- Выйти - + {!runWithoutAuth && ( + + Выйти + + )} )} diff --git a/furumi-node-player/server/.env.example b/furumi-node-player/server/.env.example index 7db502f..2ab30d6 100644 --- a/furumi-node-player/server/.env.example +++ b/furumi-node-player/server/.env.example @@ -3,6 +3,9 @@ BASE_URL=http://localhost:3001 FRONTEND_ORIGIN=http://localhost:5173 SESSION_SECRET=super-long-random-secret +# Если true/1/on/yes — сервер стартует без OIDC и не требует авторизации. +DISABLE_AUTH=false + OIDC_ISSUER_BASE_URL=https://your-issuer.example.com OIDC_CLIENT_ID=your-client-id OIDC_CLIENT_SECRET=your-client-secret diff --git a/furumi-node-player/server/src/index.ts b/furumi-node-player/server/src/index.ts index 3df02f1..59622ad 100644 --- a/furumi-node-player/server/src/index.ts +++ b/furumi-node-player/server/src/index.ts @@ -9,6 +9,10 @@ const app = express(); const port = Number(process.env.PORT ?? 3001); const frontendOrigin = process.env.FRONTEND_ORIGIN ?? 'http://localhost:5173'; +const disableAuth = ['1', 'true', 'yes', 'on'].includes( + String(process.env.DISABLE_AUTH ?? '').trim().toLowerCase(), +); + const oidcConfig = { authRequired: false, auth0Logout: false, @@ -23,10 +27,10 @@ const oidcConfig = { }, }; -if (!oidcConfig.clientID || !oidcConfig.issuerBaseURL || !oidcConfig.clientSecret) { +if (!disableAuth && (!oidcConfig.clientID || !oidcConfig.issuerBaseURL || !oidcConfig.clientSecret)) { // Keep a clear startup failure if OIDC is not configured. throw new Error( - 'OIDC config is missing. Set OIDC_ISSUER_BASE_URL, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET in server/.env', + 'OIDC config is missing. Set OIDC_ISSUER_BASE_URL, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET in server/.env (or set DISABLE_AUTH=true)', ); } @@ -38,13 +42,27 @@ app.use( ); app.use(express.json()); -app.use(auth(oidcConfig)); +if (!disableAuth) { + app.use(auth(oidcConfig)); +} app.get('/api/health', (_req, res) => { res.json({ ok: true }); }); app.get('/api/me', (req, res) => { + if (disableAuth) { + res.json({ + authenticated: false, + bypassAuth: true, + user: { + sub: 'noauth', + name: 'No Auth', + }, + }); + return; + } + if (!req.oidc.isAuthenticated()) { res.status(401).json({ authenticated: false }); return; @@ -57,17 +75,29 @@ app.get('/api/me', (req, res) => { }); app.get('/api/login', (req, res) => { + if (disableAuth) { + res.status(204).end(); + return; + } + res.oidc.login({ returnTo: frontendOrigin, }); }); app.get('/api/logout', (req, res) => { + if (disableAuth) { + res.status(204).end(); + return; + } + res.oidc.logout({ returnTo: frontendOrigin, }); }); app.listen(port, () => { - console.log(`OIDC auth server listening on http://localhost:${port}`); + console.log( + `${disableAuth ? 'NO-AUTH' : 'OIDC auth'} server listening on http://localhost:${port}`, + ); });