Skip to content

Исправление редиректа при авторизации #590

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 107 additions & 22 deletions src/frontend/auth/oidc-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,117 @@ Contributors:

export default {
login() {
window.OidcUserManager.signinRedirect()
.then(() => {
// eslint-disable-next-line no-console
console.log('User logged in');
})
.catch(error => {
// eslint-disable-next-line no-console
console.error(error);
});
try {
// Сохраняем текущий URL для возврата после авторизации
const currentPath = window.location.pathname + window.location.search + window.location.hash;
localStorage.setItem('last-visited-url', currentPath);

// Перенаправляем на страницу авторизации GitLab
window.OidcUserManager.signinRedirect()
.then(() => {
// eslint-disable-next-line no-console
console.log('Redirecting to login page...');
})
.catch(error => {
// eslint-disable-next-line no-console
console.error('Error during login redirect:', error);
});
} catch (error) {
console.error('Error during login:', error);
}
},
logout() {
window.OidcUserManager.signoutRedirect()
.then(() => {
// eslint-disable-next-line no-console
console.log('User logged out');
})
.catch(error => {
// eslint-disable-next-line no-console
console.error(error);
});
try {
// Очищаем токены
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
localStorage.removeItem('original-route');
localStorage.removeItem('last-visited-url');

// Выходим из системы
window.OidcUserManager.signoutRedirect()
.then(() => {
// eslint-disable-next-line no-console
console.log('User logged out');
})
.catch(error => {
// eslint-disable-next-line no-console
console.error('Error during logout:', error);
// В случае ошибки перенаправляем на главную страницу
window.location = window.origin + '/main';
});
} catch (error) {
console.error('Error during logout:', error);
// В случае ошибки перенаправляем на главную страницу
window.location = window.origin + '/main';
}
},
async signinCallback() {
if (window.location.hash) {
await window.OidcUserManager.signinCallback();
window.location.hash = '';
} else {
try {
// Обрабатываем callback от OIDC провайдера
if (window.location.hash) {
await window.OidcUserManager.signinCallback();
window.location.hash = '';
}

// Проверяем, авторизован ли пользователь
const user = await window.OidcUserManager.getUser();
if (!user) {
console.error('User not authenticated after signin callback');
return;
}

// Проверяем, есть ли сохраненный маршрут
const originalRoute = window.localStorage.getItem('original-route');
if (originalRoute) {
try {
const parsedRoute = JSON.parse(originalRoute);

// Удаляем сохраненный маршрут ТОЛЬКО после успешной авторизации
window.localStorage.removeItem('original-route');

// Формируем полный URL с учетом параметров и хэша
let url = parsedRoute.path;
const queryParams = new URLSearchParams();

// Добавляем параметры запроса
if (parsedRoute.query) {
Object.entries(parsedRoute.query).forEach(([key, value]) => {
queryParams.append(key, value);
});
}

// Добавляем параметры запроса к URL, если они есть
const queryString = queryParams.toString();
if (queryString) {
url += '?' + queryString;
}

// Добавляем хэш, если он есть
if (parsedRoute.hash) {
url += parsedRoute.hash;
}

// Перенаправляем на восстановленный URL
window.location = window.origin + url;
} catch (error) {
console.error('Error processing saved route:', error);
window.localStorage.removeItem('original-route');
window.location = window.origin + '/main';
}
} else {
// Проверяем, есть ли сохраненный URL в localStorage
const lastVisitedUrl = window.localStorage.getItem('last-visited-url');
if (lastVisitedUrl) {
window.localStorage.removeItem('last-visited-url');
window.location = window.origin + lastVisitedUrl;
} else {
window.location = window.origin + '/main';
}
}
} catch (error) {
console.error('Error during signin callback:', error);
// НЕ удаляем маршрут при ошибке, чтобы можно было повторить попытку
window.location = window.origin + '/main';
}
},
Expand Down
20 changes: 14 additions & 6 deletions src/frontend/components/Layouts/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,20 @@
window.$PAPI.goto(null, entity, id);
},
loginout() {
this.user ? oidcClient.logout() : oidcClient.login();
console.log("login/logout");
this.user ? oidcClient.logout() : oidcClient.login().then(() => {
window.Vuex.dispatch('setRolesFromToken');
console.log("call set roles from token");
});
if (this.user) {
// Выход пользователя
oidcClient.logout();
// Очищаем токены
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
this.user = null;
window.Vuex.dispatch('clean');
} else {
// Вход пользователя
oidcClient.login();
// После успешного входа роли будут установлены автоматически
console.log("Redirecting to login...");
}
}
}
};
Expand Down
17 changes: 12 additions & 5 deletions src/frontend/helpers/href.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,20 @@ export default {
gotoURL(ref) {
try {
if (uri.isExternalURI(ref)) {
window.open(ref, 'blank_');
window.open(ref, '_blank');
} else {
const url = new URL(ref, window.location);
if (isLocalRoute(url))
window.Router.push({ path: url.pathname, query: Object.fromEntries(url.searchParams)});
else
window.open(url, 'blank_');
if (isLocalRoute(url)) {
const fullPath = url.pathname + (url.search || '') + (url.hash || '');
window.localStorage.setItem('last-visited-url', fullPath);
window.Router.push({
path: url.pathname,
query: Object.fromEntries(url.searchParams),
hash: url.hash
});
} else {
window.open(url, '_blank');
}
}
} catch (e) {
if (env.isPlugin(Plugins.idea)) {
Expand Down
45 changes: 39 additions & 6 deletions src/frontend/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,46 @@ if (!env.isPlugin()) {
? route.query.code
: new URLSearchParams(route.hash.substr(1)).get('code');
if (OAuthCode) {
// Диспатчим событие получения OAuth-кода
window.Vuex.dispatch('onReceivedOAuthCode', OAuthCode);
const rRoute = cookie.get('return-route');
return rRoute ? JSON.parse(rRoute) : {
path: '/main',
query: {},
hash: ''
};

// Пытаемся получить сохраненный маршрут из cookie или localStorage
let rRoute = cookie.get('return-route');
const lsRoute = window.localStorage.getItem('original-route');

// Предпочитаем localStorage, если там есть данные
if (lsRoute) {
rRoute = lsRoute;
}

if (rRoute) {
try {
const parsedRoute = JSON.parse(rRoute);

// Сохраняем маршрут в localStorage для использования после авторизации
// НЕ удаляем маршрут здесь, чтобы он был доступен после перезагрузки страницы
window.localStorage.setItem('original-route', rRoute);

// Очищаем cookie, так как данные уже в localStorage
cookie.delete('return-route');

// Возвращаем маршрут для редиректа
return parsedRoute;
} catch (e) {
console.error('Error parsing saved route:', e);
return {
path: '/main',
query: {},
hash: ''
};
}
} else {
return {
path: '/main',
query: {},
hash: ''
};
}
} else {
return {
path: '/sso/error',
Expand Down
37 changes: 26 additions & 11 deletions src/frontend/router/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,40 @@ import SSOError from '@front/components/sso/SSOError';
import oidcClient from '@front/auth/oidc-client';

const middleware = (route) => {
// Проверяем, настроен ли OAuth и не авторизован ли пользователь
if (config.oauth !== false && !window.Vuex.state.isOAuthProcess && !window.Vuex.state.access_token) {
cookie.set('return-route', JSON.stringify({
// Сохраняем полный URL, включая параметры запроса, хэш и параметры маршрута
const fullRoute = {
path: route.path,
query: route.query,
hash: route.hash
}), 1);
window.location = new URL(
`/oauth/authorize?client_id=${config.oauth.APP_ID}`
+ '&redirect_uri=' + new URL(consts.pages.OAUTH_CALLBACK_PAGE, window.location)
+ `&response_type=code&state=none&scope=${config.oauth.REQUESTED_SCOPES}`
+ '&' + Math.floor(Math.random() * 10000)
, config.gitlab_server
);
hash: route.hash,
params: route.params
};

// Сохраняем в cookie и localStorage для надежности
cookie.set('return-route', JSON.stringify(fullRoute), 1);
window.localStorage.setItem('original-route', JSON.stringify(fullRoute));

// Формируем URL для авторизации с добавлением случайного параметра для предотвращения кэширования
const authUrl = new URL(
`/oauth/authorize?client_id=${config.oauth.APP_ID}`
+ '&redirect_uri=' + encodeURIComponent(new URL(consts.pages.OAUTH_CALLBACK_PAGE, window.location).toString())
+ `&response_type=code&state=none&scope=${config.oauth.REQUESTED_SCOPES}`
+ '&random=' + Math.floor(Math.random() * 10000)
, config.gitlab_server
);

// Перенаправляем на страницу авторизации
window.location = authUrl;
return;
}

// Проверяем роли пользователя, если включена ролевая модель
window.OidcUserManager.getUser().then(user => {
if (user) {
// eslint-disable-next-line no-console
console.log(user.profile.roles);
console.log('User authenticated:', user.profile.name);
console.log('User roles:', user.profile.roles);
}
});

Expand Down
Loading