Microsoft-Login auf Redirect statt Popup umgestellt (Handy/Tablet-Fix)
Der Popup-basierte Login/Logout und die stille Token-Erneuerung per Hintergrund-iFrame sind in installierten PWAs auf iOS/Android unzuverlässig - Popups werden blockiert oder verlieren die Verbindung zum öffnenden Fenster, und iOS' ITP blockiert oft den iFrame-Speicherzugriff für die stille Erneuerung. Das zwang Monteure am Handy/Tablet zu ständigen Neuanmeldungen, während es am PC funktionierte. Login/Logout laufen jetzt über einen vollen Redirect, scheiternde stille Token-Erneuerung fällt sauber auf einen Redirect zurück statt mit einem Fehler abzubrechen, und storeAuthStateInCookie ist aktiviert (Microsofts eigene Empfehlung für Safari/iOS). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b591991d19
commit
3a82a22135
@@ -18,7 +18,11 @@ export default function Header({ localUser, onLocalLogout }: { localUser: string
|
|||||||
const [themeMode, setThemeMode] = useState<ThemeMode>(getStoredTheme());
|
const [themeMode, setThemeMode] = useState<ThemeMode>(getStoredTheme());
|
||||||
|
|
||||||
function logout() {
|
function logout() {
|
||||||
if (account) instance.logoutPopup();
|
if (account) {
|
||||||
|
// Redirect statt Popup, aus demselben Grund wie beim Login (siehe Login.tsx).
|
||||||
|
instance.logoutRedirect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
onLocalLogout();
|
onLocalLogout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,17 @@ async function authHeader(): Promise<HeadersInit> {
|
|||||||
}
|
}
|
||||||
const account = msalInstance.getAllAccounts()[0];
|
const account = msalInstance.getAllAccounts()[0];
|
||||||
if (!account) throw new Error('Nicht angemeldet.');
|
if (!account) throw new Error('Nicht angemeldet.');
|
||||||
|
try {
|
||||||
const result = await msalInstance.acquireTokenSilent({ scopes: ['openid', 'profile'], account });
|
const result = await msalInstance.acquireTokenSilent({ scopes: ['openid', 'profile'], account });
|
||||||
return { Authorization: `Bearer ${result.idToken}`, 'Content-Type': 'application/json' };
|
return { Authorization: `Bearer ${result.idToken}`, 'Content-Type': 'application/json' };
|
||||||
|
} catch {
|
||||||
|
// Silent Renewal (per Hintergrund-iFrame) scheitert auf iOS/Safari häufig, weil ITP
|
||||||
|
// Drittanbieter-Speicherzugriff im iFrame blockiert. Statt mit einem kryptischen
|
||||||
|
// Fehler abzubrechen, sauber per Redirect neu anmelden – der Nutzer landet danach
|
||||||
|
// wieder genau hier.
|
||||||
|
await msalInstance.acquireTokenRedirect({ scopes: ['openid', 'profile'], account });
|
||||||
|
throw new Error('Anmeldung wird erneuert …');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function req<T>(url: string, init?: RequestInit): Promise<T> {
|
async function req<T>(url: string, init?: RequestInit): Promise<T> {
|
||||||
|
|||||||
@@ -14,7 +14,11 @@ const msalConfig: Configuration = {
|
|||||||
cache: {
|
cache: {
|
||||||
// localStorage statt sessionStorage: bleibt erhalten, wenn die (installierte) App
|
// localStorage statt sessionStorage: bleibt erhalten, wenn die (installierte) App
|
||||||
// geschlossen und neu gestartet wird – sonst müsste man sich jedes Mal neu anmelden.
|
// geschlossen und neu gestartet wird – sonst müsste man sich jedes Mal neu anmelden.
|
||||||
cacheLocation: 'localStorage'
|
cacheLocation: 'localStorage',
|
||||||
|
// Von Microsoft explizit für Safari/iOS empfohlen: hält den Auth-State zusätzlich
|
||||||
|
// in einem Cookie, da Safaris ITP die interne Silent-Renewal-/Redirect-Logik sonst
|
||||||
|
// gerne stört – genau das Symptom "am Handy ständig neu anmelden müssen".
|
||||||
|
storeAuthStateInCookie: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -8,7 +8,13 @@ import './styles.css';
|
|||||||
|
|
||||||
initTheme();
|
initTheme();
|
||||||
|
|
||||||
msalInstance.initialize().then(() => {
|
msalInstance.initialize().then(() =>
|
||||||
|
// Verarbeitet die Rückkehr von loginRedirect() (Popups sind in installierten PWAs auf
|
||||||
|
// Handys/Tablets unzuverlässig – deshalb nutzt der Microsoft-Login einen vollen
|
||||||
|
// Redirect statt eines Popups, siehe Login.tsx).
|
||||||
|
msalInstance.handleRedirectPromise()
|
||||||
|
).then(result => {
|
||||||
|
if (result?.account) msalInstance.setActiveAccount(result.account);
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<MsalProvider instance={msalInstance}>
|
<MsalProvider instance={msalInstance}>
|
||||||
|
|||||||
@@ -14,12 +14,15 @@ export default function Login({ onLocalLogin }: { onLocalLogin: (name: string) =
|
|||||||
setBusy(true);
|
setBusy(true);
|
||||||
setErr('');
|
setErr('');
|
||||||
try {
|
try {
|
||||||
await instance.loginPopup({ scopes: ['openid', 'profile'] });
|
// Redirect statt Popup: Popups werden in installierten PWAs auf Handys/Tablets
|
||||||
|
// (Homescreen-App) von iOS/Android oft blockiert oder verlieren die Verbindung
|
||||||
|
// zum öffnenden Fenster – dadurch musste man sich dort ständig neu anmelden.
|
||||||
|
await instance.loginRedirect({ scopes: ['openid', 'profile'] });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setErr(e instanceof Error ? e.message : String(e));
|
setErr(e instanceof Error ? e.message : String(e));
|
||||||
}
|
|
||||||
setBusy(false);
|
setBusy(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function submitLocal(e: FormEvent) {
|
async function submitLocal(e: FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
Reference in New Issue
Block a user