«Я люблю писать код аутентификации и авторизации». Нет Java-разработчика. Надоело строить одни и те же экраны входа снова и снова? Попробуйте API Okta для размещенной аутентификации, авторизации и многофакторной аутентификации.
Vert.x является одним из самых быстрорастущих элементов в экосистеме Spring, и обеспечение безопасности сервера Vert.x может быть сложной задачей. Развертывание Okta позволяет вам добавить безопасный единый вход на ваш сервер и одновременно предоставить вам доступ к большому количеству информации о ваших пользователях. Из этого туториала вы узнаете, как подготовить новый сервер Vert.x и интегрировать его с Okta для безопасного управления пользователями.
Краткий обзор 3-х стороннего потока OAuth
В этом примере будет использоваться поток OAuth стороннего поставщика, известный как трехсторонний поток (основа единого входа). Перед запуском в код может быть полезно краткое обновление этого процесса.
Эта проблема
Я веб-сервер, и я хочу защитить свой сайт и требовать от пользователей входа в систему. Однако написание, поддержание и управление идентификационными данными пользователей — это большая работа.
Решение
Пусть кто-то еще с этим справится. Чтобы добиться этого, требуется небольшое сотрудничество между мной (веб-сервером), моим пользователем (возможно, в веб-браузере) и тем, кто обрабатывает авторизацию для меня (в данном примере Okta). Эти три сотрудничающих участника являются тремя «ножками» трехстороннего потока OAuth. Процесс, через который они проходят, является трехсторонним рукопожатием:
- Браузер пользователя запрашивает у меня защищенный ресурс, веб-сервер
- Я, веб-сервер, решаю, что пользователь должен войти в систему первым. Я отказываюсь обслуживать запрос и вместо этого возвращаю ответ перенаправления 302, который говорит браузеру вместо этого посетить Okta
- Браузер соответствует, вместо этого посещает Okta, и пользователь входит в систему. Затем Okta возвращает собственное перенаправление 302, сообщая браузеру, что нужно вернуться и посетить меня снова … но на этот раз с секретным кодом
- Браузер посещает меня еще раз, но на этот раз я вижу, что он несет с собой этот секретный код. Теперь я делаю свой прямой звонок в Okta, обмениваясь этим секретным кодом для получения конфиденциальной информации о пользователе, такой как его имя, адрес электронной почты или номер телефона.
Вышеуказанное рукопожатие — это то, что будет происходить за кулисами после завершения этого примера. Vert.x предоставляет удобную библиотеку OAuth, чтобы позаботиться обо всем этом процессе для вас — все, что вам нужно сделать, это настроить и зарегистрировать его соответствующим образом. Это то, что демонстрирует этот урок.
В качестве руководства для начинающих этот пост предполагает только базовое знакомство с Java и некоторыми основами Java, такими как Maven. Если у вас уже работает сервер Vert.x, не стесняйтесь переходить к хорошему: вы интегрируетесь с Okta в разделе « Настройка обработчика OAuth Vert.x ».
Завершенный пример кода, включая import и pom.xml, можно найти на Github .
Запустить новый сервер Vert.x
Чтобы начать, посетите страницу Vert.x Starter и создайте новый проект. В этом руководстве вы можете оставить все значения по умолчанию и включить Vert.x Web
, OAuth
и Vert.x Config
:
После нажатия кнопки «Создать, загрузить и разархивировать локально» вы должны увидеть следующую простую структуру каталогов:
При запуске с mvn compile exec:java
из каталога demo
следует запустить сервер на порту 8080:
Посетив http://localhost:8080
в вашем браузере, вы получите обнадеживающий ответ:
На этом этапе правильным следующим шагом будет переключение на https перед продолжением добавления аутентификации. Однако, чтобы сохранить краткость и направленность учебника, эта часть будет пропущена, и в примерах будет по-прежнему использоваться режим незашифрованного http-сервера.
Внесите конфигурацию Vert.x
Vert.x предлагает универсальную конфигурационную библиотеку, хотя ее настройка немного больше, чем в Spring. В этом примере будет использовано несколько значений конфигурации, поэтому вы можете воспользоваться этой возможностью, чтобы добавить Vert.x Config в ваш проект. Зависимость уже должна присутствовать в вашем pom.xml
если вы указали Vert.x Config при создании начального проекта.
< dependency > < groupId >io.vertx</ groupId > < artifactId >vertx-config</ artifactId > < version >${vertx.version}</ version > </ dependency > |
Создайте файл с именем src/main/application.json
и добавьте следующее содержимое:
{ "clientId" : "{okta-client-id}" , "clientSecret" : "{okta-client-secret}" , "port" : 8080 } |
Вы будете обновлять эти значения в ближайшее время. Теперь в src/main/java/com/example/demo/MainVerticle.java
замените содержимое метода start()
следующим, который загрузит конфигурацию. Обратите внимание, что по завершении он вызывает метод startServer()
который еще не существует. Вы добавите это в следующем разделе.
@Override public void start() throws Exception { ConfigStoreOptions fileStore = new ConfigStoreOptions() .setType( "file" ) .setConfig( new JsonObject().put( "path" , "src/main/application.json" )); ConfigRetrieverOptions options = new ConfigRetrieverOptions() .addStore(fileStore); ConfigRetriever retriever = ConfigRetriever.create(vertx, options); retriever.getConfig(ar -> { if (ar.failed()) { System.err.println( "failed to retrieve config." ); } else { config().mergeIn(ar.result()); startServer(); } }); } |
Включите маршрутизатор Vert.x
Используя маршрутизатор Vert.x , вы сможете легко перехватывать вызовы к чувствительным конечным точкам и применять предварительную аутентификацию. Чтобы сделать это, вы теперь реализуете метод startServer()
в src/main/java/com/example/demo/MainVerticle.java
:
void startServer() { Router router = Router.router(vertx); router.route( "/private/secret" ) .handler(ctx -> { ctx.response().end( "Hi" ); }); vertx.createHttpServer() .requestHandler(router::accept) .listen(config().getInteger( "port" )); } |
В приведенном выше примере вы создали новую конечную точку в /private/secret
с целью скорейшей защиты каждой конечной точки по пути /private
. Но сначала нужно настроить обработчик OAuth Vert.x.
Создать учетную запись Okta и собрать учетные данные
Если у вас еще нет бесплатной учетной записи Okta, вы можете следовать этим инструкциям, чтобы создать ее и настроить свое первое приложение Okta. Есть четыре ключевых элемента информации, которые вам нужно собрать:
- Идентификатор клиента — например: oot9wrjjararhfaa
- Секрет клиента — (держите это в секрете!)
- Эмитент — например: https://dev-123123.oktapreview.com/oauth2/default… обязательно укажите путь / oauth2 / default !
- URL обратного вызова — это будет http: // localhost: 8080 / login, если вы следовали инструкциям выше.
Эти значения теперь можно использовать в вашем файле src/main/application.json
.
Настройте обработчик OAuth Vert.x
Vert.x поставляется с готовым OAuth-менеджером, который прекрасно интегрируется с Okta в качестве провайдера идентификации. Чтобы сохранить порядок, вы создадите отдельный фабричный метод в src/main/java/com/example/demo/MainVerticle.java
который создает настроенный обработчик OAuth. Добавьте следующее к классу MainVerticle
, заменив приведенную ниже информацию о клиенте на данные своей учетной записи, полученные из панели инструментов разработчика Okta:
AuthHandler getOAuthHandler(Router router) { OAuth2Auth oauth2 = OAuth2Auth.create(vertx, OAuth2FlowType.AUTH_CODE, new OAuth2ClientOptions() .setClientID(config().getString( "clientId" )) .setClientSecret(config().getString( "clientSecret" )) .setSite(config().getString( "issuer" )) .setTokenPath( "/v1/token" ) .setAuthorizationPath( "/v1/authorize" ) .setUserInfoPath( "/v1/userinfo" ) .setUseBasicAuthorizationHeader( false ) ); OAuth2AuthHandler authHandler = OAuth2AuthHandler.create(oauth2, config().getString( "callbackUrl" )); authHandler.extraParams(new JsonObject( "{\"scope\":\"openid profile email\"}" )); authHandler.setupCallback(router.route()); return authHandler; } |
В приведенном выше примере обратите внимание на три запрошенные области: openid , profile и email . В будущих публикациях будут рассмотрены дополнительные области действия и уровни авторизации, но на данный момент эти три будут содержать основные сведения (такие как имя пользователя и адрес электронной почты). Используя адрес электронной почты, вы также можете напрямую запросить у API Okta дополнительную информацию о пользователе и выполнить задачи по управлению аккаунтом.
Перехват и авторизация защищенных конечных точек
Теперь, когда AuthHandler
подготовлен, он должен предшествовать обработке запросов любой защищенной конечной точки и аутентифицировать пользователя. Используя подстановочный знак, чтобы зарегистрировать его в качестве обработчика верхнего уровня для всех путей ниже /private/
, его нужно будет обработать только один раз для всех будущих обработчиков, которые вы можете создать. Любой обработчик запроса ниже /private/
path может быть гарантирован, что при его вызове он будет только от правильно аутентифицированного пользователя.
Измените метод startServer()
класса MainVerticle
как указано ниже, чтобы сгенерировать и зарегистрировать обработчик:
public void startServer() { Router router = Router.router(vertx); //create and register the auth handler to intercept all //requests below the /private/ URI: AuthHandler authHandler = getOAuthHandler(router); router.route( "/private/*" ).handler(authHandler); router.route( "/private/secret" ) .handler(ctx -> { ctx.response().end( "Hi" ); }); vertx.createHttpServer() .requestHandler(router::accept) .listen(config().getString(“port”)); } |
Это было бы отличным временем, чтобы снова запустить сервер и убедиться, что все работает как положено. mvn compile java:exec
снова mvn compile java:exec
и нажав http://localhost:8080/private/secret
из вашего браузера, вы автоматически будете перенаправлены на страницу входа Okta. После входа вы должны быть перенаправлены обратно на ваш сайт, чтобы продолжить отвечать на первоначальный /private/secret
запрос.
Извлечь информацию о пользователе из JWT
Теперь, когда звонящие в ваши /private/
API-интерфейсы вошли в систему, вам нужно будет узнать их информацию. Он поставляется в виде веб-токена JSON , который необходимо извлечь и декодировать. OAuth-обработчик Vert.x скрывает это как именованный элемент строкового объекта JSON, называемого принципалом , который сам является компонентом пользовательского объекта контекста. Этот закодированный токен затем декодируется и проверяется с использованием выбранной вами библиотеки JWT. В этом примере используется библиотека верификатора JWT от Okta .
access_token
и access_token
и id_token
, но это руководство будет декодировать только id_token
. Существует аналогичная функция для декодирования access_token
если это необходимо. Для этого включите зависимость lib в Okta JWT в ваш pom.xml
:
< dependency > < groupId >com.okta.jwt</ groupId > < artifactId >okta-jwt-verifier</ artifactId > < version >0.2.0</ version > </ dependency > |
… И добавьте следующую новую функцию в класс MainVertical
:
Map<String, Object> getIdClaims(RoutingContext ctx) { try { JwtVerifier jwtVerifier = new JwtHelper() .setIssuerUrl(config().getString(“issuer”)) .setAudience( "api://default" ) .setClientId(config().getString( "clientId" )) .build(); Jwt idTokenJwt = jwtVerifier.decodeIdToken(ctx.user().principal().getString( "id_token" ), null ); return idTokenJwt.getClaims(); } catch (Exception e) { //do something with the exception... return new HashMap<>(); } } |
Вот и все! Теперь вы можете получить доступ к пользовательской информации в вашем обработчике запросов. Чтобы продемонстрировать, обработчик /private/secret
может быть обновлен для получения заявок из JWT, как показано ниже:
void startServer() { Router router = Router.router(vertx); AuthHandler authHandler = getOAuthHandler(router); router.route( "/private/*" ).handler(authHandler); router.route( "/private/secret" ).handler(ctx -> { Map claims = getIdClaims(ctx); ctx.response().end( "Hi " + claims.get( "name" ) + ", the email address we have on file for you is: " + claims.get( "email" )); }); vertx.createHttpServer().requestHandler(router::accept).listen(config().getString(“port”)); } |
С этим последним изменением, перезагружая ваш сервер и снова нажимая http://localhost:8080/private/secret
, ваш браузер должен теперь отобразить сообщение с информацией вашего аутентифицированного пользователя!
Вперед и вверх
Поздравляем, теперь у вас есть высокопроизводительный сервер Vert.x, защищенный современной системой управления безопасностью и идентификацией Okta! Okta предоставляет Java SDK для дальнейшего взаимодействия с пользователями и учетными записями, включая добавление пользовательских данных и атрибутов для ваших пользователей.
Спасибо за чтение, и, как всегда, пожалуйста, напишите нам в комментариях ниже с вопросами. Мы бы хотели, чтобы вы следили за нами в Твиттере @OktaDev или читали более интересный контент Java из нашего блога:
- Начните с Spring Security 5.0 и OIDC
- Обильное развитие с помощью Spring Boot и React
- Используйте Kong Gateway для централизации аутентификации
- Создайте базовое приложение CRUD с Angular 5.0 и Spring Boot 2.0
- Защитите свой SPA с помощью Spring Boot и OAuth
«Я люблю писать код аутентификации и авторизации». Нет Java-разработчика. Надоело строить одни и те же экраны входа снова и снова? Попробуйте API Okta для размещенной аутентификации, авторизации и многофакторной аутентификации.
Добавление единого входа на сервер Vert.x с Okta было первоначально опубликовано в блоге разработчиков Okta 11 января 2018 года.