Spring Security OAuth2 с несколькими IDPL и формой входа: совпадающие пользователи

#spring-boot #spring-security #oauth-2.0 #spring-security-oauth2

#spring-boot #spring-безопасность #oauth-2.0 #spring-security-oauth2

Вопрос:

Я использовал Spring Security несколько раз в нескольких проектах, включая трехэтапную аутентификацию OAuth2 на шлюзе API Zuul и т.д. Все работает блестяще, а официальная документация очень аккуратная и простая.

Но есть один момент, который я все еще не понимаю из документов. Представьте, что у вас есть сервер ресурсов на базе spring с несколькими поставщиками идентификаторов, а также у вас есть собственная база данных пользователей и форма входа.

Таким образом, пользователи могут проходить аутентификацию либо через форму входа, либо через один из IDPL (скажем, Google или Facebook).

Вопрос в том, как сопоставить аутентификацию из любого из ваших IDPL с объектом аутентификации, который улучшен / сопоставлен с вашим локальным пользователем?

Т.е. у Алисы есть учетная запись в вашей системе (в вашей базе данных). Она заходит в свой «профиль» и заявляет, что у нее также есть учетная запись Google или Facebook. ХОРОШО, готово, вы сохраняете эту информацию где-нибудь в своей системе.

Теперь, когда Алиса входит в вашу систему через социальную сеть, какой spring API вы используете, чтобы понять, что Алиса, введенная через Google, — это точно такая же Алиса, которая уже зарегистрирована в вашей базе данных? В каком API вы улучшаете ее аутентификацию с помощью полномочий на основе вашей базы данных?

Заранее спасибо, ребята

Комментарии:

1. Рассматривали ли вы возможность использования собственного сервера OAuth2, который принимал бы третьих лиц (Google, Facebook …) и поддерживал бы создание собственных пользователей? Тогда ваше приложение будет иметь дело только с токенами, выданными вашим поставщиком авторизации.

2. Точно) Вот как это работает в одном из наших проектов. Но здесь у нас есть другие требования (

Ответ №1:

Обычно это делается путем создания составного файла, который содержит как OidcUser объект, так и объект вашего домена. Например:

 @Component
public class MyOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
    private final OidcUserService delegate = new OidcUserService();

    @Override
    public OidcUser loadUser(OidcUserRequest oidcUserRequest) {
        // the information that comes back from google, et al
        OidcUser oidcUser = this.delegate.loadUser(oidcUserRequest);

        // the information from your DB
        MyUser user = this.myRepository.findUserByXYZ(oidcUser.getXYZ());

        return new MyOidcUser(user, oidcUser);
    }

    private static class MyOidcUser extends MyUser implements OidcUser {
        private final OidcUser delegate;

        public MyOidcUser(MyUser user, OidcUser oidcUser) {
            super(user);
            this.delegate = oidcUser;
        }

        // ... implement delegate methods
    }
} 
  

Обратите внимание, что XYZ есть некоторый атрибут, который позволяет вам узнать, что пользователь из Google является пользователем из вашей системы. Может быть, это адрес электронной почты, например.

Преимущество этой дополнительной части работы заключается в том, что Spring Security поместит этот MyOidcUser объект в Authentcation#getPrincipal . Итак, теперь, если вам нужно получить биты вашего домена, вы это делаете (MyUser) authentication.getPrincipal() , но если вам нужны биты OIDC, вы это делаете (OidcUser) authentication.getPrincipal() . В зависимости от ваших вариантов использования вы можете сделать что-то такое простое, как:

 @GetMapping("/endpoint1")
public String endpoint1(@AuthenticationPrincipal MyUser myUser) {
    // ...
}

@GetMapping("/endpoint2")
public String endpoint2(@AuthenticationPrincipal OidcUser oidcUser) {
    URL issuer = oidcUser.getIdToken().getIssuer();
    // ...
}