feat: Add logout for oidc (#2840)
* add oidc logout route, button in menu * removed old comments * use local storage to trigger signout in other tabs * refactored to make use useEffect * cleaned up comments * fix remove event listener * moved remove leftover storage variable to beginning of usemount Co-authored-by: Michael Andersen <Michael.Andersen@rmp.uhn.ca>
This commit is contained in:
1 parent
e401358887
commit
1d47f31738
7 files changed
+119
-46
No files matched your search
@@ -28,7 +28,6 @@ let commandsManager, extensionManager, servicesManager, hotkeysManager;
|
||||
|
||||
function App({ config, defaultExtensions, defaultModes }) {
|
||||
const [init, setInit] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const run = async () => {
|
||||
appInit(config, defaultExtensions, defaultModes)
|
||||
|
||||
@@ -322,13 +322,13 @@ function WorkList({
|
||||
seriesTableDataSource={
|
||||
seriesInStudiesMap.has(studyInstanceUid)
|
||||
? seriesInStudiesMap.get(studyInstanceUid).map(s => {
|
||||
return {
|
||||
description: s.description || '(empty)',
|
||||
seriesNumber: s.seriesNumber || '',
|
||||
modality: s.modality || '',
|
||||
instances: s.numSeriesInstances || '',
|
||||
};
|
||||
})
|
||||
return {
|
||||
description: s.description || '(empty)',
|
||||
seriesNumber: s.seriesNumber || '',
|
||||
modality: s.modality || '',
|
||||
instances: s.numSeriesInstances || '',
|
||||
};
|
||||
})
|
||||
: []
|
||||
}
|
||||
>
|
||||
@@ -346,7 +346,7 @@ function WorkList({
|
||||
<Link
|
||||
key={i}
|
||||
to={`${mode.routeName}?StudyInstanceUIDs=${studyInstanceUid}`}
|
||||
// to={`${mode.routeName}/dicomweb?StudyInstanceUIDs=${studyInstanceUid}`}
|
||||
// to={`${mode.routeName}/dicomweb?StudyInstanceUIDs=${studyInstanceUid}`}
|
||||
>
|
||||
<Button
|
||||
rounded="full"
|
||||
@@ -354,7 +354,7 @@ function WorkList({
|
||||
disabled={!isValidMode}
|
||||
endIcon={<Icon name="launch-arrow" />} // launch-arrow | launch-info
|
||||
className={classnames('font-bold', { 'ml-2': !isFirst })}
|
||||
onClick={() => {}}
|
||||
onClick={() => { }}
|
||||
>
|
||||
{t(`Modes:${mode.displayName}`)}
|
||||
</Button>
|
||||
@@ -414,6 +414,17 @@ function WorkList({
|
||||
},
|
||||
];
|
||||
|
||||
if (appConfig.oidc) {
|
||||
menuOptions.push({
|
||||
icon: 'power-off',
|
||||
title: t('Header:Logout'),
|
||||
onClick: () => {
|
||||
navigate(`/logout?redirect_uri=${encodeURIComponent(window.location.href)}`);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames('bg-black h-full', {
|
||||
|
||||
@@ -41,10 +41,7 @@ const initUserManager = (oidc, routerBasename) => {
|
||||
|
||||
const openIdConnectConfiguration = Object.assign({}, firstOpenIdClient, {
|
||||
redirect_uri: _makeAbsoluteIfNecessary(redirect_uri, baseUri),
|
||||
silent_redirect_uri: _makeAbsoluteIfNecessary(
|
||||
silent_redirect_uri,
|
||||
baseUri
|
||||
),
|
||||
silent_redirect_uri: _makeAbsoluteIfNecessary(silent_redirect_uri, baseUri),
|
||||
post_logout_redirect_uri: _makeAbsoluteIfNecessary(
|
||||
post_logout_redirect_uri,
|
||||
baseUri
|
||||
@@ -52,6 +49,17 @@ const initUserManager = (oidc, routerBasename) => {
|
||||
});
|
||||
|
||||
return getUserManagerForOpenIdConnectClient(openIdConnectConfiguration);
|
||||
};
|
||||
|
||||
function LogoutComponent(props) {
|
||||
const { userManager } = props;
|
||||
localStorage.setItem('signoutEvent', 'true');
|
||||
const location = useLocation();
|
||||
const query = new URLSearchParams(location.search);
|
||||
userManager.signoutRedirect({
|
||||
post_logout_redirect_uri: query.get('redirect_uri'),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
function LoginComponent(userManager) {
|
||||
@@ -60,9 +68,7 @@ function LoginComponent(userManager) {
|
||||
const loginHint = queryParams.get('login_hint');
|
||||
const targetLinkUri = queryParams.get('target_link_uri');
|
||||
if (iss !== oidcAuthority) {
|
||||
console.error(
|
||||
'iss of /login does not match the oidc authority'
|
||||
);
|
||||
console.error('iss of /login does not match the oidc authority');
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -96,22 +102,22 @@ function LoginComponent(userManager) {
|
||||
}
|
||||
|
||||
function OpenIdConnectRoutes({
|
||||
oidc,
|
||||
routerBasename,
|
||||
UserAuthenticationService
|
||||
}) {
|
||||
oidc,
|
||||
routerBasename,
|
||||
UserAuthenticationService,
|
||||
}) {
|
||||
const userManager = initUserManager(oidc, routerBasename);
|
||||
|
||||
const getAuthorizationHeader = () => {
|
||||
const user = UserAuthenticationService.getUser();
|
||||
|
||||
return {
|
||||
Authorization: `Bearer ${user.access_token}`
|
||||
Authorization: `Bearer ${user.access_token}`,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const handleUnauthenticated = () => {
|
||||
userManager.signinRedirect()
|
||||
userManager.signinRedirect();
|
||||
|
||||
// return null because this is used in a react component
|
||||
return null;
|
||||
@@ -119,23 +125,45 @@ function OpenIdConnectRoutes({
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
//for multi-tab logout
|
||||
useEffect(() => {
|
||||
localStorage.removeItem('signoutEvent');
|
||||
const storageEventListener = event => {
|
||||
const signOutEvent = localStorage.getItem('signoutEvent');
|
||||
if (signOutEvent) {
|
||||
navigate(
|
||||
`/logout?redirect_uri=${encodeURIComponent(window.location.href)}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('storage', storageEventListener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('storage', storageEventListener);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
UserAuthenticationService.set({ enabled: true });
|
||||
|
||||
UserAuthenticationService.setServiceImplementation({
|
||||
getAuthorizationHeader,
|
||||
handleUnauthenticated
|
||||
handleUnauthenticated,
|
||||
});
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
const oidcAuthority = oidc[0].authority;
|
||||
|
||||
const location = useLocation();
|
||||
const { pathname, search } = location;
|
||||
|
||||
const redirect_uri = new URL(userManager.settings._redirect_uri).pathname//.replace(routerBasename,'')
|
||||
const silent_refresh_uri = new URL(userManager.settings._silent_redirect_uri).pathname//.replace(routerBasename,'')
|
||||
const post_logout_redirect_uri = new URL(userManager.settings._post_logout_redirect_uri).pathname//.replace(routerBasename,'');
|
||||
const redirect_uri = new URL(userManager.settings._redirect_uri).pathname; //.replace(routerBasename,'')
|
||||
const silent_refresh_uri = new URL(userManager.settings._silent_redirect_uri)
|
||||
.pathname; //.replace(routerBasename,'')
|
||||
const post_logout_redirect_uri = new URL(
|
||||
userManager.settings._post_logout_redirect_uri
|
||||
).pathname; //.replace(routerBasename,'');
|
||||
|
||||
// const pathnameRelative = pathname.replace(routerBasename,'');
|
||||
|
||||
@@ -148,10 +176,7 @@ function OpenIdConnectRoutes({
|
||||
|
||||
return (
|
||||
<Routes basename={routerBasename}>
|
||||
<Route
|
||||
path={silent_refresh_uri}
|
||||
onEnter={window.location.reload}
|
||||
/>
|
||||
<Route path={silent_refresh_uri} onEnter={window.location.reload} />
|
||||
<Route
|
||||
path={post_logout_redirect_uri}
|
||||
element={
|
||||
@@ -167,22 +192,36 @@ function OpenIdConnectRoutes({
|
||||
/>
|
||||
<Route
|
||||
path={redirect_uri}
|
||||
element={<CallbackPage userManager={userManager} onRedirectSuccess={(user) => {
|
||||
const { pathname, search = '' } = JSON.parse(
|
||||
sessionStorage.getItem('ohif-redirect-to')
|
||||
);
|
||||
element={
|
||||
<CallbackPage
|
||||
userManager={userManager}
|
||||
onRedirectSuccess={user => {
|
||||
const { pathname, search = '' } = JSON.parse(
|
||||
sessionStorage.getItem('ohif-redirect-to')
|
||||
);
|
||||
|
||||
UserAuthenticationService.setUser(user);
|
||||
UserAuthenticationService.setUser(user);
|
||||
|
||||
navigate({
|
||||
pathname,
|
||||
search
|
||||
})
|
||||
}}/>}
|
||||
navigate({
|
||||
pathname,
|
||||
search,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/login"
|
||||
element={<LoginComponent userManager={userManager} oidcAuthority={oidcAuthority}/>}
|
||||
element={
|
||||
<LoginComponent
|
||||
userManager={userManager}
|
||||
oidcAuthority={oidcAuthority}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/logout"
|
||||
element={<LogoutComponent userManager={userManager} />}
|
||||
/>
|
||||
</Routes>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user