Рубрики
Без рубрики

Извлечение принципала и полномочий с помощью Spring Security OAuth

Узнайте, как извлечь информацию о пользователе в настройке OAuth.

Автор оригинала: 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 и аутентификации пользователей через третью сторону мы должны рассмотреть три шага:

  1. Аутентификация пользователя – пользователь аутентифицируется с третьей стороной
  2. Авторизация пользователя – следует за аутентификацией, это когда пользователь позволяет нашему приложению выполнять определенные операции от их имени; именно здесь области действия вступают в силу
  3. Извлечение пользовательских данных – используйте полученный нами токен 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(Map map) {
        return map.get("login");
    }
}

В зависимости от подписки нашего пользователя на Github – бесплатно или иным образом – мы дадим им GITHUB_USER_SUBSCRIBED или GITHUB_USER_FREE полномочия:

public class GithubAuthoritiesExtractor 
  implements AuthoritiesExtractor {
    List GITHUB_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(Map map) {
        return map.get("name");
    }
}

Что касается полномочий, наш сервер авторизации уже помещает их в свои данные userinfo-uri .

Таким образом, мы собираемся извлекать и обогащать их:

public class BaeldungAuthoritiesExtractor 
  implements AuthoritiesExtractor {

    @Override
    public List extractAuthorities
      (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