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}`,
+ );
});