Never Build Auth Again — Любите строить управление пользователями? С Okta вы можете за считанные минуты добавить в приложение социальную регистрацию, многофакторную аутентификацию и поддержку OpenID Connect. Создайте бесплатный аккаунт разработчика сегодня.
Когда вы создаете свое Java-приложение, управление пользователями является критическим фактором. Для приложений и API характерно разделять доступ к различным частям приложения в зависимости от ролей, назначенных пользователю — это управление доступом на основе ролей (RBAC).
Вот тут и приходит Okta — Okta упрощает это, управляя ролями внутри групп (пользователи могут принадлежать к одной или нескольким группам). Благодаря интеграции Okta Spring Security этот процесс становится автоматизированным благодаря использованию общих аннотаций, которые сопоставляют группы с конкретными ролями и разрешают или запрещают доступ. Это делается с помощью обычных аннотаций Spring Security, которые мы описали ниже.
Чтобы продемонстрировать это на практике, ниже я собрал демо, в котором описан простой, но общий сценарий. В нашем примере мы рассмотрим сочетание незащищенных страниц, страниц, к которым имеет доступ только аутентифицированный пользователь, и страниц, которые требуют от пользователей дополнительного уровня авторизации, прежде чем они смогут получить к ним доступ.
Мы добавили весь код, на который мы ссылаемся здесь.
Если вы уже хотите погрузиться и начать работать со встроенным RBAC для вашего Java-приложения, просто подключите своего клиента Okta к приложению Spring Boot здесь .
Если у вас есть какие-либо вопросы, свяжитесь со службой поддержки Okta здесь.
Шаг первый: Настройте свою учетную запись Okta
Первый шаг — настройка вашего арендатора Okta. Таким образом, вы можете запустить пример приложения, которое мы создали, и увидеть это в действии. Зарегистрируйте учетную запись разработчика здесь, а затем выполните следующие действия:
- Создать группу
admins - Создать группу
users - Создать пользователя, который принадлежит к группам
users - Создайте второго пользователя, который принадлежит к обеим группам
- Создать приложение OpenID Connect (OIDC)
- Добавьте две группы в приложение
- Настройте сервер авторизации по умолчанию для включения членства в группах в токены доступа
Давайте пройдемся по тому, как это выглядит:
Настройка групп
В меню панели инструментов администратора Okta найдите « Users и нажмите « Groups . Нажмите « Add Group введите admins в поле « Name и добавьте описание группы, например: «Администраторы». Нажмите Add Group чтобы завершить этот шаг.
Следуйте тому же процессу, чтобы добавить группу users .
Настройка пользователей
Снова перейдите к « Users на панели инструментов администратора Okta, но на этот раз нажмите « People . Нажмите Add User и заполните форму с информацией о пользователе. (Используйте реальный адрес электронной почты для основного или дополнительного адреса электронной почты — и тот, к которому у вас есть доступ — чтобы вы могли проверить почту позже.) В поле Groups добавьте этих пользователей в группу users вы создали ранее. Убедитесь, что вы установили флажок « Send user activation email now а затем нажмите «Сохранить и добавить другого».
Повторите шаги, описанные выше, только на этот раз добавьте второго пользователя в группы users и admins .
Перейдите на свою электронную почту и проверьте эти адреса электронной почты. Нажмите на ссылки для обоих пользователей, чтобы активировать их.
Создание приложения OIDC
Теперь пришло время настроить слой аутентификации.
На информационной панели администратора Okta выберите Applications в меню, а затем нажмите Add Application .
Выберите Web и нажмите Next .
Когда вам будет предложено заполнить форму, используйте эти значения:
| Field | Value || ------------------- | ------------------------------ || Name | Fun with Spring Security Roles || Base URIs | http://localhost:8080/ || Login redirect URIs | http://localhost:8080/ || Group assignments | `admins` and `users` || Grant type allowed | Check: `Implicit` | |
Когда вы будете готовы, нажмите `Done`, и вы увидите получившуюся страницу ниже:
Указанные URI являются значениями по умолчанию для Spring Boot. Вы можете легко изменить их позже.
Прежде чем перейти к следующему шагу, прокрутите вниз и запишите Client ID . Он понадобится вам для настройки приложения Spring Boot.
Настройка вашего сервера авторизации
Затем найдите API в меню панели администратора Okta и нажмите « Authorization Servers чтобы запустить следующее:
Обратите внимание на Issuer URI . Это также понадобится вам позже для настройки приложения Spring Boot.
Нажмите «По default и выберите вкладку « Claims ». Нажмите Add Claim и заполните поля следующим образом:
| Field | Value || --------------------- | ------------ || Name | groups || Include in token type | Access Token || Value type | Groups || Filter | Regex .* || Include in | Any scope | |
Нажмите Create чтобы завершить этот шаг.
Создание этого утверждения гарантирует, что информация о членстве в группе будет включена в токен доступа при аутентификации пользователя. Этот шаг очень важен для подключения к ролям и механизмам безопасности Spring Security
Шаг второй: настройте приложение Spring Boot
Сначала клонируем по этой ссылке.
Откройте проект в выбранной вами IDE или редакторе. Скриншоты ниже отсюда.
Сделайте копию файла application.yml.sample и назовите его application.yml
Помните те значения, которые мы пометили, чтобы сохранить ранее? Обновите свою информацию с теми. Вот наш пример:
| Name | Value || ----------- | ------------------------------------------------- || baseUrl | https://dev-237330.oktapreview.com || issuer | https://dev-237330.oktapreview.com/oauth2/default || audience | api://default || clientId | 0oacdldhkydGGruON0h7 || rolesClaim | groups || redirectUri | http://localhost:8080/ | |
Прежде чем мы перейдем к коду, давайте посмотрим на приложение в действии.
Запустите это из командной строки, чтобы начать:
mvn spring-boot:run |
Смотрите приложение в действии
Перейдите на домашнюю страницу и нажмите « Login .
Чтобы войти, используйте учетные данные для пользователя, который принадлежит к группе Users вы создали на первом шаге. Оттуда вы увидите, что приложение отображает вашу пользовательскую информацию и отображает ряд кнопок под ней.
Они соответствуют разрешениям на доступ в приложении. Члены группы users смогут видеть страницу при нажатии Users Only . Это тот же случай для пользователей группы admins , которые могут видеть страницу, когда Admins Only admins .
Посмотрим, как это работает.
Нажмите Users Only . Вы увидите страницу, которая показывает, что вы являетесь членом группы users .
Нажмите Back и затем нажмите Admins Only . На этот раз вы получите страницу 403 Unauthorized потому что вы не являетесь членом группы admins .
Нажмите Logout и войдите снова, но на этот раз как пользователь, который принадлежит к обеим группам (второй пользователь, которого вы создали на первом шаге).
Нажмите Admins Only .
На этот раз вы увидите, что вы находитесь в группах admins и users .
Довольно просто! Теперь давайте прыгнем в код …
Шаг третий: проверка кода безопасности Spring
В этом разделе описывается, как группы Okta связываются с ролями Spring Security.
Демо- приложение использует следующее:
- Весенний ботинок
- Spring Security
- Spring Security OAuth2
- Okta Spring Security Starter
- Шаблоны с тимьяном
- Дополнения Thymeleaf для Spring Security 4
- Okta Sign-In Widget
Мы зависим от okta-spring-security-starter (из pom.xml). Вот как происходит закулисная магия:
...<dependency> <groupId>com.okta.spring</groupId> <artifactId>okta-spring-security-starter</artifactId> <version>0.1.0</version></dependency>... |
Давайте начнем с Javascript Okta Sign-In Widget и посмотрим, как он соединяет клиентскую сторону с Spring Boot.
Настройка виджета входа в Okta
Вот как мы настроили виджет входа в Okta в шаблоне Thymeleaf `login.html`:
$( document ).ready(function() { var data = { baseUrl: [[${appProperties.baseUrl}]], clientId: [[${appProperties.clientId}]], redirectUri: [[${appProperties.redirectUri}]], authParams: { issuer: [[${appProperties.issuer}]], responseType: ['token'] } }; window.oktaSignIn = new OktaSignIn(data); // Check if we already have an access token var token = oktaSignIn.tokenManager.get('token'); if (token) { window.location.href = "/authenticated"; } else { renderWidget(); }}); |
В строках 3–8 вы увидите, что мы встроили все параметры для подключения к нашему клиенту Okta в качестве встроенных переменных шаблона Thymeleaf. Эти значения передаются из контроллера Spring Boot как часть модели. Делая это, вы должны указать эти настройки только один раз — теперь и серверная, и клиентская стороны могут убедиться в них. Ниже мы рассмотрим, как управлять этими настройками (все они взяты из файла application.yml ).
После того, как мы настроили и создали экземпляр Okta Sign-In Widget, следующий шаг — проверить, вошел ли пользователь в систему. Затем мы предпринимаем одно из двух действий. Если они есть, мы отправляем их на страницу /authenticated . Если нет, мы отображаем виджет, который дает пользователю возможность войти в систему.
Вот функция renderWidget :
function renderWidget() { oktaSignIn.renderEl( {el: '#okta-login-container'}, function (response) { // check if success if (response.status === 'SUCCESS') { // for our example we have the id token and the access token oktaSignIn.tokenManager.add('token', response[0]); if (!document.location.protocol.startsWith('https')) { console.log( 'WARNING: You are about to pass a bearer token in a cookie over an insecure\n' + 'connection. This should *NEVER* be done in a production environment per\n' + ); } document.cookie = 'access_token=' + oktaSignIn.tokenManager.get('token').accessToken; document.location.href = "/authenticated"; } }, function (err) { // handle any errors console.log(err); } );} |
Как только виджет отображается на странице, внутренняя логика вступает во владение на основе ваших настроек, когда пользователь входит в систему. В этом случае вы используете этот поток и получите только токен доступа, указанный параметром responseType конфигурации ,
При успешном входе в систему вы вводите функцию обратного вызова с объектом response . Объект ответа имеет ваш (или в данном случае ваш пользователь) токен доступа.
Строка 19 устанавливает cookie с токеном доступа, а строка 20 отправляет (теперь аутентифицированного) пользователя в /authenticated конечную точку.
На этом этапе Spring Security может распознать прошедшего проверку пользователя.
Прежде чем мы рассмотрим роли Spring Security, давайте посмотрим, как Spring Security работает с токеном доступа.
Spring Security Token Extractor
По умолчанию плагин Spring Security OAuth 2.0 обрабатывает токены доступа, входящие в заголовок Authorization как токен канала-носителя. Это хорошо для приложений, которые создают ответы RESTful для клиентов, таких как клиент Angular.
Для этого примера я сохранил архитектуру и количество Javascript минимальными, поэтому я хотел полных переходов страницы. Это немного старая школа, но она держит небольшой пример кода.
Чтобы Spring Security распознала, что пользователь прошел аутентификацию, нам нужно, чтобы он мог обрабатывать токен, поступающий в cookie.
К счастью, Spring Security позволяет довольно просто переопределить поведение по умолчанию, установив TokenExtractor . Вот код, который делает это происходящим из OktaSpringSecurityRolesExampleApplication :
@Beanprotected ResourceServerConfigurerAdapter resourceServerConfigurerAdapter() { return new ResourceServerConfigurerAdapter() { ... @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.tokenExtractor(new TokenExtractor() { @Override public Authentication extract(HttpServletRequest request) { String tokenValue = findCookie(ACCESS_TOKEN_COOKIE_NAME, request.getCookies()); if (tokenValue == null) { return null; } return new PreAuthenticatedAuthenticationToken(tokenValue, ""); } ... }); } };} |
Для этого необходимо извлечь токен доступа из списка файлов cookie на входящий запрос, если это возможно. Затем анализ и проверка выполняется автоматически. Вуаля!
Установление контроля доступа на основе ролей
В настройках приложения вы определяете, какие пути открыты. Для всех других путей требуется как минимум аутентифицированный сеанс.
Вот еще одна выдержка из приложения OktaSpringSecurityRolesExampleApplication :
@Beanprotected ResourceServerConfigurerAdapter resourceServerConfigurerAdapter() { return new ResourceServerConfigurerAdapter() { @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/", "/login", "/images/**").permitAll() .and() .exceptionHandling().accessDeniedHandler(customAccessDeniedHandler); } ... };} |
В этом случае вы говорите Spring Security разрешить любому не прошедшему проверку подлинности пользователю доступ к домашней странице ( / ), странице входа ( /login ) и всему, что происходит из папки статических изображений. Это означает, что любой другой путь автоматически ограничен по умолчанию.
На этом этапе вы также определяете пользовательский обработчик отказа в доступе.
@Controllerpublic class SecureController { @Autowired protected AppProperties appProperties; @RequestMapping("/authenticated") public String authenticated(Model model) { model.addAttribute("appProperties", appProperties); return "authenticated"; } @RequestMapping("/users") @PreAuthorize("hasAuthority('users')") public String users() { return "roles"; } @RequestMapping("/admins") @PreAuthorize("hasAuthority('admins')") public String admins() { return "roles"; } @RequestMapping("/403") public String error403() { return "403"; }} |
В этом контроллере мы определили четыре пути, которые требуют минимум аутентификации пользователя.
Реальная ценность /admins путях /users и /admins . Обратите внимание, что у них обоих есть аннотация @PreAuthorize . Это означает, что следующее выражение должно быть удовлетворено до того, как метод будет введен. Функция hasAuthority подтверждает, принадлежит ли аутентифицированный пользователь к этим ролям. В этом примере они автоматически сопоставляются с группами Okta, которые мы создали ранее, поэтому было важно включить утверждение groups в маркер доступа от Okta.
Хотя это требует некоторой настройки, теперь у вас есть контроль доступа на основе ролей всего с одной строкой кода!
Сквозная конфигурация
На стороне клиента у нас есть набор HTML-страниц в форме шаблонов Thymeleaf, которые подаются из самого приложения. Из-за этого имеет смысл иметь единый источник значений конфигурации, требуемый как клиентом, так и сервером.
Это легко с аннотациями Spring @Component и @ConfigurationProperties .
Вот класс AppProperties :
@Component@ConfigurationProperties("okta.oauth")public class AppProperties { private String issuer; private String audience; private String clientId; private String rolesClaim; private String baseUrl; private String redirectUri; ... getters and setters ...} |
@ConfigurationProperties сообщает Spring, чтобы он @ConfigurationProperties все свойства из файла application.yml , принадлежащего okta.oauth .
Аннотация @Component заставляет Spring создать экземпляр этого объекта и сделать его доступным для автоматического подключения в другом месте.
Взгляните на этот фрагмент из HomeController :
@Controllerpublic class HomeController { @Autowired protected AppProperties appProperties; ... @RequestMapping("/login") public String login(Model model) { model.addAttribute("appProperties", appProperties); return "login"; }} |
Перед возвратом представления login в login при достижении конечной точки /login объект AppProperties (автоматически подключенный в строках 4 и 5) добавляется в модель.
Вот что делает его доступным для шаблона Thymeleaf, как вы видели ранее:
<script th:inline="javascript"> /*<![CDATA[*/ $( document ).ready(function() { var data = { baseUrl: [[${appProperties.baseUrl}]], clientId: [[${appProperties.clientId}]], redirectUri: [[${appProperties.redirectUri}]], authParams: { issuer: [[${appProperties.issuer}]], responseType: ['token'] } }; window.oktaSignIn = new OktaSignIn(data); ... }); ... /*]]>*/</script> |
Начните кодировать!
Вот и все! Попробуй и дай мне знать, как это происходит! Я в твиттере.
Хотя я рассказал о преимуществах использования механизма групп Okta с контролем доступа Spring на основе ролей, команда разработчиков Java-приложений Okta также усердно работает над SDK следующего поколения и интеграциями. Следите за будущими выпусками новой Okta Java Spring Boot Integration, которая будет иметь поддержку других рабочих процессов OIDC, включая code а также размещенные, настраиваемые представления входа и регистрации.
Этот пост был адаптирован отсюда.
Never Build Auth Again — Любите строить управление пользователями? С Okta вы можете за считанные минуты добавить в приложение социальную регистрацию, многофакторную аутентификацию и поддержку OpenID Connect. Создайте бесплатный аккаунт разработчика сегодня.









