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
:
@Bean protected 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
:
@Bean protected 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
) и всему, что происходит из папки статических изображений. Это означает, что любой другой путь автоматически ограничен по умолчанию.
На этом этапе вы также определяете пользовательский обработчик отказа в доступе.
@Controller public 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
:
@Controller public 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. Создайте бесплатный аккаунт разработчика сегодня.