2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-17 20:45:44 +00:00

save auth context

This commit is contained in:
Matthias Mair
2025-01-20 20:01:21 +01:00
parent 67d89b549f
commit 0249114322
4 changed files with 71 additions and 33 deletions

View File

@ -5,7 +5,7 @@ import type { AxiosRequestConfig } from 'axios';
import type { Location, NavigateFunction } from 'react-router-dom';
import { api, setApiDefaults } from '../App';
import { ApiEndpoints } from '../enums/ApiEndpoints';
import { apiUrl } from '../states/ApiState';
import { apiUrl, useServerApiState } from '../states/ApiState';
import { useLocalState } from '../states/LocalState';
import { useUserState } from '../states/UserState';
import { type Provider, fetchGlobalStates } from '../states/states';
@ -66,6 +66,7 @@ export const doBasicLogin = async (
) => {
const { host } = useLocalState.getState();
const { clearUserState, setToken, fetchUserState } = useUserState.getState();
const { setAuthContext } = useServerApiState.getState();
if (username.length == 0 || password.length == 0) {
return;
@ -90,6 +91,7 @@ export const doBasicLogin = async (
}
)
.then((response) => {
setAuthContext(response.data?.data);
if (response.status == 200 && response.data?.meta?.is_authenticated) {
setToken(response.data.meta.access_token);
loginDone = true;
@ -98,6 +100,7 @@ export const doBasicLogin = async (
})
.catch((err) => {
if (err?.response?.status == 401) {
setAuthContext(err.response.data?.data);
const mfa_flow = err.response.data.data.flows.find(
(flow: any) => flow.id == 'mfa_authenticate'
);
@ -173,32 +176,23 @@ export function handleReset(
values: { email: string }
) {
ensureCsrf();
api
.post(
apiUrl(ApiEndpoints.user_reset),
values
/*{
headers: { Authorization: '' }
api.post(apiUrl(ApiEndpoints.user_reset), values).then((val) => {
if (val.status === 200) {
notifications.show({
title: t`Mail delivery successful`,
message: t`Check your inbox for a reset link. This only works if you have an account. Check in spam too.`,
color: 'green',
autoClose: false
});
navigate('/login');
} else {
notifications.show({
title: t`Reset failed`,
message: t`Check your input and try again.`,
color: 'red'
});
}
*/
)
.then((val) => {
if (val.status === 200) {
notifications.show({
title: t`Mail delivery successful`,
message: t`Check your inbox for a reset link. This only works if you have an account. Check in spam too.`,
color: 'green',
autoClose: false
});
navigate('/login');
} else {
notifications.show({
title: t`Reset failed`,
message: t`Check your input and try again.`,
color: 'red'
});
}
});
});
}
export function handleMfaLogin(
@ -207,9 +201,11 @@ export function handleMfaLogin(
values: { code: string }
) {
const { setToken } = useUserState.getState();
const { setAuthContext } = useServerApiState.getState();
authApi(apiUrl(ApiEndpoints.auth_login_2fa), undefined, 'post', {
code: values.code
}).then((response) => {
setAuthContext(response.data?.data);
setToken(response.data.meta.access_token);
followRedirect(navigate, location?.state);
});

View File

@ -574,7 +574,9 @@ async function runActionWithFallback(
action: () => Promise<ResultType>,
getReauthText: (props: any) => any
) {
const { setAuthContext } = useServerApiState.getState();
const rslt = await action().catch((err) => {
setAuthContext(err.response.data?.data);
// check if we need to re-authenticate
if (err.status == 401) {
if (
@ -603,9 +605,14 @@ async function runActionWithFallback(
name: 'TOTP',
description: t`Enter your TOTP or recovery code`
})
}).then(() => {
action();
});
})
.then((response) => {
setAuthContext(response.data?.data);
action();
})
.catch((err) => {
setAuthContext(err.response.data?.data);
});
} else if (rslt == ResultType.reauth) {
authApi(apiUrl(ApiEndpoints.auth_reauthenticate), undefined, 'post', {
password: await getReauthText({
@ -613,9 +620,14 @@ async function runActionWithFallback(
name: 'password',
description: t`Enter your password`
})
}).then(() => {
action();
});
})
.then((response) => {
setAuthContext(response.data?.data);
action();
})
.catch((err) => {
setAuthContext(err.response.data?.data);
});
}
}

View File

@ -4,13 +4,15 @@ import { createJSONStorage, persist } from 'zustand/middleware';
import { api } from '../App';
import { emptyServerAPI } from '../defaults/defaults';
import { ApiEndpoints } from '../enums/ApiEndpoints';
import type { AuthConfig, ServerAPIProps } from './states';
import type { AuthConfig, AuthContext, ServerAPIProps } from './states';
interface ServerApiStateProps {
server: ServerAPIProps;
setServer: (newServer: ServerAPIProps) => void;
fetchServerApiState: () => void;
auth_config?: AuthConfig;
auth_context?: AuthContext;
setAuthContext: (auth_context: AuthContext) => void;
sso_enabled: () => boolean;
registration_enabled: () => boolean;
sso_registration_enabled: () => boolean;
@ -47,6 +49,10 @@ export const useServerApiState = create<ServerApiStateProps>()(
});
},
auth_config: undefined,
auth_context: undefined,
setAuthContext(auth_context) {
set({ auth_context });
},
sso_enabled: () => {
const data = get().auth_config?.socialaccount.providers;
return !(data === undefined || data.length == 0);

View File

@ -50,6 +50,30 @@ export interface ServerAPIProps {
django_admin: null | string;
}
export interface AuthContext {
status: number;
data: { flows: Flow[] };
meta: { is_authenticated: boolean };
}
export enum FlowEnum {
VerifyEmail = 'verify_email',
Login = 'login',
Signup = 'signup',
ProviderRedirect = 'provider_redirect',
ProviderSignup = 'provider_signup',
ProviderToken = 'provider_token',
MfaAuthenticate = 'mfa_authenticate',
Reauthenticate = 'reauthenticate',
MfaReauthenticate = 'mfa_reauthenticate'
}
export interface Flow {
id: FlowEnum;
providers?: string[];
is_pending?: boolean[];
}
export interface AuthConfig {
account: {
authentication_method: string;