Автор оригинала: Daniel Barrigas.
1. Обзор
В этом руководстве мы проиллюстрируем, как создать приложение, которое делегирует проверку подлинности пользователя третьей стороне, а также настраиваемому серверу авторизации с помощью Spring Boot и Spring Security OAuth.
Кроме того, мы продемонстрируем, как извлечь оба Principal и Authorities , используя интерфейсы Spring PrincipalExtractor и AuthoritiesExtractor .
Для ознакомления с Spring Security OAuth2, пожалуйста, обратитесь к этим статьям.
2. Зависимости Maven
Чтобы начать работу, нам нужно добавить зависимость spring-security-oauth2-auto configure в ваш pom.xml :
org.springframework.security.oauth.boot spring-security-oauth2-autoconfigure 2.2.6.RELEASE
3. Аутентификация OAuth С Помощью Github
Далее, давайте создадим конфигурацию безопасности нашего приложения:
@Configuration @EnableOAuth2Sso public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/**") .authorizeRequests() .antMatchers("/login**") .permitAll() .anyRequest() .authenticated() .and() .formLogin().disable(); } }
Короче говоря, мы говорим, что любой может получить доступ к конечной точке /login и что все остальные конечные точки потребуют аутентификации пользователя.
Мы также аннотировали наш класс конфигурации с помощью @EnableOAuthSso , который преобразует наше приложение в клиент OAuth и создает необходимые компоненты, чтобы оно вело себя как таковое.
Хотя Spring создает большинство компонентов для нас по умолчанию, нам все равно нужно настроить некоторые свойства:
security.oauth2.client.client-id=89a7c4facbb3434d599d security.oauth2.client.client-secret=9b3b08e4a340bd20e866787e4645b54f73d74b6a security.oauth2.client.access-token-uri=https://github.com/login/oauth/access_token security.oauth2.client.user-authorization-uri=https://github.com/login/oauth/authorize security.oauth2.client.scope=read:user,user:email security.oauth2.resource.user-info-uri=https://api.github.com/user
Вместо того, чтобы заниматься управлением учетными записями пользователей, мы делегируем его третьей стороне – в данном случае Github – что позволяет нам сосредоточиться на логике нашего приложения.
4. Извлечение Принципала и полномочий
При работе в качестве клиента OAuth и аутентификации пользователей через третью сторону мы должны рассмотреть три шага:
- Аутентификация пользователя – пользователь аутентифицируется с третьей стороной
- Авторизация пользователя – следует за аутентификацией, это когда пользователь позволяет нашему приложению выполнять определенные операции от их имени; именно здесь области действия вступают в силу
- Извлечение пользовательских данных – используйте полученный нами токен OAuth для извлечения пользовательских данных
Как только мы получим данные пользователя, Spring сможет автоматически создать Принципала и Полномочия пользователя .
Хотя это может быть приемлемо, чаще всего мы оказываемся в ситуации, когда хотим иметь полный контроль над ними.
Для этого Spring предоставляет нам два интерфейса, которые мы можем использовать для переопределения его поведения по умолчанию :
- PrincipalExtractor – Интерфейс, который мы можем использовать для предоставления нашей пользовательской логики для извлечения Principal
- AuthoritiesExtractor – Аналогично PrincipalExtractor , но вместо этого он используется для настройки Authorities извлечения
По умолчанию Spring предоставляет два компонента – FixedPrincipalExtractor и FixedAuthoritiesExtractor |– , которые реализуют эти интерфейсы и имеют заранее определенную стратегию их создания для нас.
4.1. Настройка аутентификации Github
В нашем случае мы знаем, как выглядят пользовательские данные Github как и что мы можем использовать, чтобы адаптировать их в соответствии с нашими потребностями.
Таким образом, чтобы переопределить компоненты Spring по умолчанию, нам просто нужно создать два компонента Bean , которые также реализуют эти интерфейсы.
Для нашего приложения Principal мы просто будем использовать имя пользователя Github:
public class GithubPrincipalExtractor implements PrincipalExtractor { @Override public Object extractPrincipal(Mapmap) { return map.get("login"); } }
В зависимости от подписки нашего пользователя на Github – бесплатно или иным образом – мы дадим им GITHUB_USER_SUBSCRIBED или GITHUB_USER_FREE полномочия:
public class GithubAuthoritiesExtractor implements AuthoritiesExtractor { ListGITHUB_FREE_AUTHORITIES = AuthorityUtils.commaSeparatedStringToAuthorityList( "GITHUB_USER,GITHUB_USER_FREE"); List GITHUB_SUBSCRIBED_AUTHORITIES = AuthorityUtils.commaSeparatedStringToAuthorityList( "GITHUB_USER,GITHUB_USER_SUBSCRIBED"); @Override public List extractAuthorities (Map map) { if (Objects.nonNull(map.get("plan"))) { if (!((LinkedHashMap) map.get("plan")) .get("name") .equals("free")) { return GITHUB_SUBSCRIBED_AUTHORITIES; } } return GITHUB_FREE_AUTHORITIES; } }
Затем нам также нужно создать бобы, используя эти классы:
@Configuration @EnableOAuth2Sso public class SecurityConfig extends WebSecurityConfigurerAdapter { // ... @Bean public PrincipalExtractor githubPrincipalExtractor() { return new GithubPrincipalExtractor(); } @Bean public AuthoritiesExtractor githubAuthoritiesExtractor() { return new GithubAuthoritiesExtractor(); } }
4.2. Использование Пользовательского сервера авторизации
Мы также можем использовать наш собственный сервер авторизации для наших пользователей – вместо того, чтобы полагаться на третью сторону.
Несмотря на сервер авторизации, который мы решили использовать, компоненты, необходимые для настройки как Principal , так и Authorities , остаются неизменными: PrincipalExtractor и AuthoritiesExtractor .
Нам просто нужно знать о данных, возвращаемых user-info-url endpoint , и использовать их так, как мы считаем нужным.
Давайте изменим наше приложение, чтобы аутентифицировать наших пользователей с помощью сервера авторизации, описанного в этой статье:
security.oauth2.client.client-id=SampleClientId security.oauth2.client.client-secret=secret security.oauth2.client.access-token-uri=http://localhost:8081/auth/oauth/token security.oauth2.client.user-authorization-uri=http://localhost:8081/auth/oauth/authorize security.oauth2.resource.user-info-uri=http://localhost:8081/auth/user/me
Теперь, когда мы указываем на наш сервер авторизации, нам нужно создать оба экстрактора; в этом случае наш PrincipalExtractor собирается извлечь Principal из Карты , используя имя ключ:
public class BaeldungPrincipalExtractor implements PrincipalExtractor { @Override public Object extractPrincipal(Mapmap) { return map.get("name"); } }
Что касается полномочий, наш сервер авторизации уже помещает их в свои данные userinfo-uri .
Таким образом, мы собираемся извлекать и обогащать их:
public class BaeldungAuthoritiesExtractor implements AuthoritiesExtractor { @Override public ListextractAuthorities (Map map) { return AuthorityUtils .commaSeparatedStringToAuthorityList(asAuthorities(map)); } private String asAuthorities(Map map) { List authorities = new ArrayList<>(); authorities.add("BAELDUNG_USER"); List > authz = (List >) map.get("authorities"); for (LinkedHashMap entry : authz) { authorities.add(entry.get("authority")); } return String.join(",", authorities); } }
Затем мы добавим бобы в наш класс Security Config :
@Configuration @EnableOAuth2Sso public class SecurityConfig extends WebSecurityConfigurerAdapter { // ... @Bean public PrincipalExtractor baeldungPrincipalExtractor() { return new BaeldungPrincipalExtractor(); } @Bean public AuthoritiesExtractor baeldungAuthoritiesExtractor() { return new BaeldungAuthoritiesExtractor(); } }
5. Заключение
В этой статье мы реализовали приложение, которое делегирует аутентификацию пользователя третьей стороне, а также настраиваемому серверу авторизации, и продемонстрировали, как настроить как Принципал , так и Полномочия .
Как обычно, реализацию этого примера можно найти на Github .
При локальном запуске вы можете запустить и протестировать приложение по адресу localhost:8082