dev
RekHoto 2 years ago
parent bc7db43a1a
commit 2d9ff8831a

@ -11,6 +11,7 @@
"dependencies": {
"@ant-design/icons": "^5.0.1",
"@nanostores/react": "^0.4.1",
"@react-keycloak/web": "^3.4.0",
"@tanstack/react-query": "^4.24.9",
"@turf/bbox": "^6.5.0",
"@turf/helpers": "^6.5.0",
@ -20,6 +21,7 @@
"chart.js": "^4.4.0",
"immer": "^9.0.19",
"immutable": "^4.3.0",
"keycloak-js": "^23.0.1",
"lodash.debounce": "^4.0.8",
"mapbox-gl": "npm:empty-npm-package@1.0.0",
"maplibre-gl": "^2.4.0",

@ -11,7 +11,8 @@ import { usePendingPointsFilters } from "./stores/usePendingPointsFilters";
import { useOnApprovalPointsFilters } from "./stores/useOnApprovalPointsFilters";
import { useWorkingPointsFilters } from "./stores/useWorkingPointsFilters";
import useLocalStorage from "./hooks/useLocalStorage.js";
import { ReactKeycloakProvider } from "@react-keycloak/web";
import { keycloak } from "./keycloak.js";
const queryClient = new QueryClient();
enableMapSet();
@ -35,6 +36,7 @@ function App() {
}
return (
<ReactKeycloakProvider authClient={keycloak}>
<QueryClientProvider client={queryClient}>
<BrowserRouter basename={import.meta.env.BASE_URL}>
<Routes>
@ -45,6 +47,7 @@ function App() {
</Routes>
</BrowserRouter>
</QueryClientProvider>
</ReactKeycloakProvider>
);
}

@ -1,16 +1,9 @@
import { Button, Popover, Tooltip } from "antd";
import { ArrowRightOutlined, LogoutOutlined } from "@ant-design/icons";
import { api } from "./api";
import { setAuth } from "./stores/auth";
import { useQuery } from "@tanstack/react-query";
import { Title } from "./components/Title";
export const logOut = () => {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
localStorage.removeItem('expires_in');
setAuth(false);
};
import { keycloak } from "./keycloak.js";
export function SignOut() {
const { data } = useQuery(["profile"], async () => {
@ -24,7 +17,7 @@ export function SignOut() {
content={
<>
<Title text={data?.username} classNameText={"lowercase"} />
<Button type="primary" block onClick={logOut}>
<Button type="primary" block onClick={keycloak.logout}>
<span className="mr-1">Выйти</span>
<ArrowRightOutlined />
</Button>

@ -1,21 +1,17 @@
import { useStore } from "@nanostores/react";
import { Spin } from "antd";
import { Navigate } from "react-router-dom";
import { isAuthorized$, userInfoLoading$ } from "./stores/auth";
import { useKeycloak } from "@react-keycloak/web";
export function WithAuth(props) {
const isAuthorized = useStore(isAuthorized$);
const userInfoLoading = useStore(userInfoLoading$);
const { keycloak } = useKeycloak();
if (userInfoLoading) {
return <Spin className="user-info-loader" />;
const login = async () => {
await keycloak.login();
}
if (isAuthorized) {
if (keycloak.authenticated) {
return <>{props.children}</>;
} else {
login()
}
return <Navigate to="/signin" replace={true} />;
return <></>;
}

@ -7,6 +7,8 @@ import { appendFiltersInUse } from "./utils.js";
import { useMode } from "./stores/useMode.js";
import { useMemo } from "react";
import { useUpdateLayerCounter } from "./stores/useUpdateLayerCounter.js";
import { keycloak } from "./keycloak.js";
import { useKeycloak } from "@react-keycloak/web";
export const BASE_URL = import.meta.env.VITE_API_URL;
@ -17,10 +19,10 @@ export const api = axios.create({
: BASE_URL,
});
api.interceptors.request.use(function (config) {
const token = localStorage.getItem("access_token");
api.interceptors.request.use(async function (config) {
const token = keycloak.token;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
config.headers.Authorization = `Bearer ${ token }`;
}
return config;
@ -235,14 +237,14 @@ const TASK_STATUSES = {
finished: "Перерасчет ML завершен"
}
export const useCanEdit = () => {
const { data } = useGetPermissions();
const { keycloak } = useKeycloak();
const { data: statusData } = useLastMLRun();
const hasFinishedUpdate = useMemo(() => {
return statusData?.task_status === TASK_STATUSES.finished
}, [statusData]);
return data === "editor" && hasFinishedUpdate;
return keycloak.hasResourceRole("postnet_editor", "postnet") && hasFinishedUpdate;
};
export const useUpdatePostamatId = () => {

@ -0,0 +1,7 @@
import Keycloak from "keycloak-js";
export const keycloak = new Keycloak({
url: import.meta.env.VITE_KEYCLOAK_URL,
realm: "SST",
clientId: import.meta.env.VITE_KEYCLOAK_CLIENT_ID,
});

@ -3,27 +3,13 @@ import { Alert, Button, Form, Input, Space, Typography } from "antd";
import { LockOutlined, UserOutlined } from "@ant-design/icons";
import React from "react";
import { Navigate } from "react-router-dom";
import { isAuthorized$, refreshTokenIntervalFunction, setAuthLocalStorage } from "../stores/auth";
import { signin, signinError$, signinLoading$ } from "../stores/signin";
import { isAuthorized$ } from "../stores/auth";
import { signinError$, signinLoading$ } from "../stores/signin";
function LoginForm() {
const signinError = useStore(signinError$);
const signinLoading = useStore(signinLoading$);
const onFinish = async (values) => {
const data = await signin(values);
setAuthLocalStorage(data);
let interval;
setTimeout(async () => {
await refreshTokenIntervalFunction();
interval = setInterval(async () => {
await refreshTokenIntervalFunction();
}, (data.expires_in - 5) * 1000)
}, 0);
};
return (
<Space direction="vertical" style={{ width: "320px" }}>
{signinError.length > 0 ? (

@ -1,6 +1,4 @@
import { action, atom } from "nanostores";
import { api } from "../api";
import { logOut } from "../SignOut.jsx";
export const userInfoLoading$ = atom(true);
@ -9,67 +7,3 @@ export const isAuthorized$ = atom(false);
export const setAuth = action(isAuthorized$, "setAuth", (store, newValue) => {
store.set(newValue);
});
export const refreshToken = () => {
const url = import.meta.env.VITE_KEYCLOAK_URL || 'https://kk.dev.selftech.ru/';
const clientId = import.meta.env.VITE_KEYCLOAK_CLIENT_ID || 'postnet';
const clientSecret = import.meta.env.VITE_KEYCLOAK_CLIENT_SECRET || 'K2yHweEUispkVeWn03VMk843sW2Moic5';
return api.request({
url: "/realms/SST/protocol/openid-connect/token",
baseURL: url,
method: "POST",
data: {
grant_type: "refresh_token",
client_id: clientId,
client_secret: clientSecret,
token_type: "bearer",
refresh_token: localStorage.getItem("refresh_token")
},
headers: {
'Content-type': 'application/x-www-form-urlencoded',
},
});
}
export const setAuthLocalStorage = (data) => {
localStorage.setItem("access_token", data.access_token);
localStorage.setItem("refresh_token", data.refresh_token);
localStorage.setItem("expires_in", data.expires_in);
}
export const refreshTokenIntervalFunction = async () => {
try {
const { data: refreshData } = await refreshToken();
setAuthLocalStorage(refreshData);
} catch (error) {
clearInterval(interval);
logOut();
throw error;
}
}
async function checkAuth() {
try {
const { data } = await refreshToken();
setAuthLocalStorage(data);
let interval;
setTimeout(async () => {
await refreshTokenIntervalFunction();
interval = setInterval(async () => {
await refreshTokenIntervalFunction();
}, (data.expires_in - 5) * 1000)
}, 0);
setAuth(true);
} catch (e) {
console.log("Not authorized");
clearInterval(interval);
} finally {
userInfoLoading$.set(false);
}
}
checkAuth();

Loading…
Cancel
Save