Уважаемые разработчики исправьте уже этот косяк. Всего в Java есть четыре модификатора доступа. Перечислим их в порядке от самых строгих до самых «мягких»: private; default (package visible); protected; public.
Дмитрий Воробьёв Уровень 14
14 июня 2022
я из 2022, где лекция про геттеры и сеттеры?
Сообщество
JavaRush — это интерактивный онлайн-курс по изучению Java-программирования c нуля. Он содержит 1200 практических задач с проверкой решения в один клик, необходимый минимум теории по основам Java и мотивирующие фишки, которые помогут пройти курс до конца: игры, опросы, интересные проекты и статьи об эффективном обучении и карьере Java‑девелопера.
Подписывайтесь
Язык интерфейса
Скачивайте наши приложения
Этот веб-сайт использует данные cookie, чтобы настроить персонально под вас работу сервиса. Используя веб-сайт, вы даете согласие на применение данных cookie. Больше подробностей — в нашем Пользовательском соглашении.
Источник: javarush.com
Как взломать программу
Как сделать Private Routes с авторизацией через JWT token
JWT token (он же JSON Web Token) — это строка, состоящая из трех частей: заголовок, данные и подпись.
Посетитель сайта хочет прочитать свою переписку. Он заходит на страницу с диалогами, и сайт отправляет запрос на получение контента (списка сообщений), при этом к запросу прикрепляется специальная строка — JWT токен. С помощью этой строки сервер проверяет, авторизован ли пользователь, и решает, направить ли ему в ответ контент сайта (список сообщений).
Существует два вида JWT-токенов: access-token и refresh-token, которые создаются и используются только в паре. Эту пару токенов генерирует сервер и выдает конкретному пользователю в ответ на запрос авторизации. При этом каждому из токенов назначается «срок жизни» — период времени, в течение которого токен будет распознаваться бекендом как валидный. Для этого сервер сохраняет выданную пару токенов в своей базе данных, а при новой авторизации заменяет у себя информацию о токенах и их валидности токенов.
1.1. Access-токен
Особенностью access-токена является то, что он хранится локально на frontend-части сайта в localStorage, и его необходимо каждый раз записывать в заголовки запросов на бекенд.
С помощью access-токена мы получаем доступ к функциям сайта, которые зависят от бекенда (получают данные от бекенда). Это, в основном данные для страниц, доступных авторизованным пользователям ( список сообщений, возможность оставить комментарий, удалить свой пост).
Это работает следующим образом: пользователь нажимает кнопку «загрузить историю сообщений». Сайт генерирует GET-запрос на бекенд, добавляет в headers запроса данные Access-токена. Бекенд, соответственно, считывает заголовки, проверяет валидность токена и направляет пользователю ответ со списком сообщений, который доступен только авторизованным пользователям.
Взлом программ через OllyDBG
1.2. Refresh-токен
Когда у access-токена заканчивается срок действия, на помощь приходит refresh-токен.
Этот токен отличается тем, что хранится в cookies, и поэтому всегда автоматически прицепляется к запросам на бекенд.
С помощью refresh-токена мы обновляем устаревший («протухший») access-токен. Для этого мы отправляем запрос на специальный endpoint бекенда (обычно «/api/refresh»), а в ответ сервер генерирует новую пару access token + refresh token.
Далее цикл повторяется: сервер сохраняет информацию о новой валидной паре access-token + refresh-token, а сайт прикрепляет новый access-token к заголовкам новых запросов.
Если до сих пор не понятно, есть очень крутой и понятный ролик на ютуб.
2. Авторизация через JWT token (теория)
Авторизация с использованием JWT token реализуется с помощью двух основных паттернов:
- первичная авторизация (т.е. когда пользователь первый раз зашел на сайт, либо когда пользователь последний раз авторизовался очень давно, и пара JWT-токенов устарела)
- авторизация через обновление токена (т.е. когда пользователь авторизовался на сайте, затем закрыл вкладку, сбросив хранящееся в переменной состояние isAuth, и далее заново открыл вкладку с сайтом; но при этом пара JWT-токенов либо refresh-токен не успели устареть)
2.1. Авторизация с нуля (первичная авторизация )
- Посетитель переходит на страницу авторизации http://my_awesome_web_app.com/login.
- Посетитель вводит логин и пароль в форму авторизации, и нажимает кнопку «Авторизоваться» («Login»).
- Запрос авторизации с введенными ранее логином и паролем отправляются на сервер.
- Сервер проверяет, есть ли такая пара логин + пароль в его базе данных с пользователями.
- Если такой пользователь не найден, сервер отправляет в ответ ошибку.
- Если логин и пароль введены верно, сервер генерирует для пользователя пару токенов access token + refresh token, и сразу же записывает refresh токен в httpOnly cookie.
- Далее сервер создает ответ об успешной авторизации, и записывает в body ответа сгенерированный access token. Ответ направляется пользователю.
- Сайт принимает ответ сервера и записывает access token из ответа в свой localStorage. Также для целей доступа пользователя к приватным страничкам сайт создает и устанавливает переменную isAuth = true.
- Далее ко всем запросам пользователя добавляется access token, и сервер дает ответ пользователю как авторизованному (например, сервер считывает из accessToken id пользователя и может дать ему список его друзей или его сообщений).
2.2. Авторизация через обновление токена
- Посетитель переходит на любую страницу сайта http://my_awesome_web_app.com/news.
- Если для просмотра страницы http://my_awesome_web_app.com/news не требуется авторизация, сайт показывает эту страничку.
- Если для просмотра страницы http://my_awesome_web_app.com/my_messages нужна авторизация, сайт показывает нам «крутилку», и в это время пытается обновить авторизацию на основе ранее полученных токенов.
- Сайт пробует считать access токен из localStorage, и направить запрос на получение данных пользователя (аватарки, имени пользователя и т.п.).
- Если access token окажется валидным, то с сервера в ответ придут данные пользователя, и сайт может установить переменную isAuth = true. Далее, соответственно, пользователь перенаправляется на страничку, которую изначально хотел посмотреть.
- Если access token окажется невалидным, то с сервера в ответ придет ошибка. Эту ошибку нужно перехватить и попробовать обновить авторизацию через refresh token. То есть в тот момент, когда пришел ответ с ошибкой, перехватить ошибку и направить запрос на адрес «/api/refresh». К этому запросу автоматически прицепляется cookies с refresh-токеном.
- При успешном обновлении авторизации сервер выдает пользователю новую пару access token + refresh token, и далее пользователь сможет сделать успешный запрос за получением данных пользователя, и, соответственно, статуса isAuth = true на сайте. Далее, соответственно, пользователь перенаправляется на страничку, которую изначально хотел посмотреть.
- При неудачной попытке обновления авторизации, устанавливается переменная isAuth = false, и пользователь перенаправляется на страницу авторизации, либо на домашнюю страницу сайта.
3. Что требуется для JWT авторизации на frontend
3.1. Создать проект
Введите в консоли: npx create-react-app jwt-auth-app
Если не знаете, как создать новый проект на React:
3.2. Настроить axios
Введите в консоли: npm install axios
В папке src/ создадим файл api.config.js , в котором пропишем для axios добавление accessToken к запросам и обновление токенов при невалидном accessToken.
Код для добавления перехватчиков к axios-запросам:
import axios from «axios»; export const instance = axios.create(< // к запросу будет приуепляться cookies withCredentials: true, baseURL: «https://jsonplaceholder.typicode.com/», >); // создаем перехватчик запросов // который к каждому запросу добавляет accessToken из localStorage instance.interceptors.request.use( (config) => < config.headers.Authorization = `Bearer $` return config > ) // создаем перехватчик ответов // который в случае невалидного accessToken попытается его обновить // и переотправить запрос с обновленным accessToken instance.interceptors.response.use( // в случае валидного accessToken ничего не делаем: (config) => < return config; >, // в случае просроченного accessToken пытаемся его обновить: async (error) => < // предотвращаем зацикленный запрос, добавляя свойство _isRetry const originalRequest = ; originalRequest._isRetry = true; if ( // проверим, что ошибка именно из-за невалидного accessToken error.response.status === 401 // проверим, что запрос не повторный error.config !error.config._isRetry ) < try < // запрос на обновление токенов const resp = await instance.get(«/api/refresh»); // сохраняем новый accessToken в localStorage localStorage.setItem(«token», resp.data.accessToken); // переотправляем запрос с обновленным accessToken return instance.request(originalRequest); >catch (error) < console.log(«AUTH ERROR»); >> // на случай, если возникла другая ошибка (не связанная с авторизацией) // пробросим эту ошибку throw error; > );
- Введите в консоли: npm install axios
В папке src/ создадим файл api.auth.js , в котором пропишем запросы на backend:
import < instance >from «./api.config.js»; export default const AuthService < login (email, password) < return instance.post(«/api/login», ) > refreshToken() < return instance.get(«/api/refresh»); >logout() < return instance.post(«/api/logout») >>
4. Создаем Private Routes
На многих сайтах существует два вида страниц: с общим доступом и приватные.
Страницы с общим доступом может открыть любой посетитель сайта (например, новости, информация о компании, а также страница авторизации).
Приватные страницы доступны только авторизованным пользователям, иначе они автоматически отправляют неавторизованного посетителя на страницу авторизации.
Для того, чтобы сайт знал, авторизован ли пользователь, необходимо хранить эту информацию в двух глобальных переменных: isAuth , isAuthInProgress .
4.1. Установим React Router
Введите в консоли: npm install react-router react-router-dom
4.2. Создадим переменные isAuth, isAuthInProgress
Эти переменные можно создать и хранить в state-менеджере (redux, mobX), можно создать специальный AuthContext, также можно хранить их в useState, либо создать хук, который будет обновлять авторизацию и возвращать объект с указанными переменными.
Разберем это на примере хранения переменных в mobX.
Введите в консоли: npm install mobx mobx-react-lite
В папке src/ создадим файл store.js , в котором пропишем указанные переменные.
Код файла store.js:
import < makeAutoObservable >from «mobx»; import AuthService from «./api.auth.js»; class AuthStore < isAuth = false; isAuthInProgress = false; constructor() < makeAutoObservable(this, <>, < autoBind: true >); > async login(email, password) < this.isAuthInProgress = true; try < const resp = await AuthService.login(email, password); localStorage.setItem(«token», resp.data.accessToken); this.isAuth = true; >catch (err) < console.log(«login error»); >finally < this.isAuthInProgress = false; >> async checkAuth() < this.isAuthInProgress = true; try < const resp = await AuthService.refresh(); localStorage.setItem(«token», resp.data.accessToken); this.isAuth = true; >catch (err) < console.log(«login error»); >finally < this.isAuthInProgress = false; >> async logout() < this.isAuthInProgress = true; try < await AuthService.logout(); this.isAuth = false; localStorage.removeItem(«token»); >catch (err) < console.log(«logout error»); >finally < this.isAuthInProgress = false; >> > export default new AuthStore();
4.3. Создадим HOC PrivateRoute
В папке src/ создадим файл privateRoute.jsx , в котором пропишем логику privateRoute:
- если процесс авторизации не завершен, то ждем, когда сервер пришлет ответ об удачной/неудачной попытке авторизации
- если пришел ответ от сервера, и авторизация успешна, тогда показываем пользователю запрошенную приватную страничку
- если пришел ответ от сервера, но авторизация неуспешна, то перенаправляем пользователя на страницу авторизации
import < Navigate, Outlet, Route >from «react-router-dom»; import authStore from «./store.js»; import < observer >from «mobx-react-lite»; const PrivateRoute = (props) => < if (authStore.isLoadingAuth) < return Checking auth. ; > if (authStore.isAuth) < return > else < return ; > >; export default observer(PrivateRoute);
используется для отображения children (вместо props.children)
В папке src/ редактируем файл App.jsx , в котором добавим приватные роуты.
import React, < useEffect >from «react»; import < Route, Routes, BrowserRouter >from «react-router-dom»; import < observer >from «mobx-react-lite»; import AuthStore from «./store.js»; import PrivateRoute from «./privateRoute.js»; import LoginPage from «./pages/loginPage»; import UsersPage from «./pages/usersPage»; const App = observer(() => < useEffect(() =>< AuthStore.checkAuth(); >, []); return ( //страница, для посещения которой авторизация не требуется > /> //страницы, для посещения которых требуется авторизация >> > /> > /> 404. not found > /> ); >); export default App;
Успех!
Вот и готова первая JWT-авторизация на фронтенде. Всем работающего кода, даже когда у тебя лапки
Источник: habr.com