Как зарегистрировать нового пользователя через Spring Social Facebook?

У меня есть веб-сайт (приложение Angular), доступ к которому я могу получить на https: // локальный: 4200, и сервер (чистый REST API), который находится на https: // локальный: 8443.

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


Согласно документы

POST /signin/{providerId} - Initiates the sign in flow.

вот почему есть кнопка, которая делает именно это:

<form ngNoForm name = "fb_signin" id = "fb_signin" action = "https://localhost:8443/signin/facebook" method = "POST">
  <input type = "hidden" name = "scope" value = "email">
  <button type = "submit">SIGNING</button>
</form>

Оттуда какое-то время все работает нормально. Пользователь перенаправляется на страницу авторизации Facebook, где нажимается кнопка авторизации. После этого пользователь перенаправляется на https: // localhost: 8443 / signin / facebook.


Похоже, что по умолчанию, если пользователь неизвестен, будет другое перенаправление на https: // localhost: 8443 / регистрация (см. документы)

If the provider user ID matches more than one existing connection, ProviderSignInController will redirect to the application’s sign in URL to offer the user a chance to sign in through another provider or with their username and password. The request to the sign in URL will have an "error" query parameter set to "multiple_users" to indicate the problem so that the page can communicate it to the user. The default sign in URL is "/signin" (relative to the application root), but can be customized by setting the signInUrl property.

На моем сервере это выглядит так (заимствовано из образца приложения):

@RequestMapping(value = "/signup", method = RequestMethod.GET)
public SignUpForm signupForm(WebRequest request) {
    Connection<?> connection = providerSignInUtils.getConnectionFromSession(request);
    if (connection != null) {
        request.setAttribute("message", new Message(MessageType.INFO, "Your " + StringUtils.capitalize(connection.getKey().getProviderId()) + " account is not associated with a Spring Social Showcase account. If you're new, please sign up."), WebRequest.SCOPE_REQUEST);
        return SignUpForm.fromProviderUser(connection.fetchUserProfile());
    } else {
        return new SignUpForm();
    }
}

И вот мои проблемы:

Прежде всего мне нужно знать, что я должен делать в этой конечной точке. Пользователь авторизовал мое приложение, но мой сервер еще не знает пользователя, поэтому я

  • connection.fetchUserProfile() и сохраните нового пользователя в моей базе данных
  • что-то другое?

Во-вторых, я не знаю, как я должен перенаправить отсюда обратно на свой веб-сайт, который, как объяснялось, находится на https: // локальный: 4200. Но, конечно, мой сервер этого не знает.

Есть ли шанс, что кто-нибудь сможет помочь мне в этом?


Это SocialConfig

@Configuration
@EnableSocial
public class SocialConfig implements SocialConfigurer {

    private final static Logger LOGGER = LogManager.getLogger(SocialConfig.class);

    @Value("${spring.social.facebook.appId}")
    String facebookAppId;

    @Value("${spring.social.facebook.appSecret}")
    String facebookSecret;

    @Autowired
    private DataSource dataSource;

    @Bean
    @Scope(value = "singleton", proxyMode = ScopedProxyMode.INTERFACES)
    public ConnectionFactoryLocator connectionFactoryLocator() {
        ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();

        registry.addConnectionFactory(new FacebookConnectionFactory(
                facebookAppId,
                facebookSecret
        ));

        return registry;
    }

    @Bean
    @Scope(value = "singleton", proxyMode=ScopedProxyMode.INTERFACES)
    public UsersConnectionRepository usersConnectionRepository() {
        return new JdbcUsersConnectionRepository(dataSource, connectionFactoryLocator(), Encryptors.noOpText());
    }

    @Override
    public void addConnectionFactories(ConnectionFactoryConfigurer cfConfig, Environment env) {
        LOGGER.debug("Adding connection factories");
        cfConfig.addConnectionFactory(new FacebookConnectionFactory(
                env.getProperty("facebook.clientId"),
                env.getProperty("facebook.clientSecret")));

    }

    @Override
    public UserIdSource getUserIdSource() {
        return new AuthenticationNameUserIdSource();
    }

    @Override
    public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
        return new JdbcUsersConnectionRepository(dataSource, connectionFactoryLocator, Encryptors.noOpText());
    }

    @Bean
    public ProviderSignInController providerSignInController(
            ConnectionFactoryLocator connectionFactoryLocator,
            UsersConnectionRepository usersConnectionRepository) {
        ProviderSignInController controller = new ProviderSignInController(
                connectionFactoryLocator,
                usersConnectionRepository,
                new SimpleSignInAdapter(new HttpSessionRequestCache()));

        return controller;
    }

    @Bean
    public RequestCache requestCache() {
        return new HttpSessionRequestCache();
    }

    @Bean
    public SignInAdapter signInAdapter() {
        return new SimpleSignInAdapter(new HttpSessionRequestCache());
    }

}

Зависимости Maven, связанные с Spring Social:

<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-facebook</artifactId>
    <version>3.0.0.M1</version>
</dependency>
<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-security</artifactId>
    <version>2.0.0.M4</version>
</dependency>
<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-core</artifactId>
    <version>2.0.0.M2</version>
</dependency>
<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-config</artifactId>
    <version>2.0.0.M2</version>
</dependency>

Посмотрите, поможет ли учебник в этом вопросе SO stackoverflow.com/questions/49942640/…?

Tarun Lalwani 10.05.2018 15:22

@TarunLalwani Хм, нет, это другая установка, и я думаю, что проблема также отличается от того, что у меня есть. Я знаю, почему происходят перенаправления - я не знаю, как перенаправить обратно на веб-клиент, который размещается где-то еще.

Stefan Falk 10.05.2018 15:45
5
2
725
2

Ответы 2

After that the user gets redirected to https://localhost:8443/signin/facebook.

Я думаю, что есть еще один лучший способ сделать это. Поскольку ваше угловое веб-приложение (https: // локальный: 4200) состоит из веб-слоя, поэтому прямое перенаправление через действие формы не лучший способ. Вы можете использовать Прокси-маршрутизациякликните сюда

Теперь, если вы используете прокси-маршрутизацию, вам необходимо настроить порт прокси (8443) с помощью команды.

ng serve –proxy-config proxy.conf.json
where proxy.conf.json contain your configuration https://localhost:8443/

тогда вам нужно сначала аутентифицировать каждого пользователя / нового пользователя на вашем сервере (уровень обслуживания), а затем передавать каждый запрос через контроллер уровня обслуживания пользователя. Это приведет к передаче каждого запроса через ваш сервер и решит вашу проблему.

The user authorized my app, but my server does not know the user yet so do I

Простите, я не понимаю. локальный: 8443 / вход / facebook - это мое перенаправление OAuth с Facebook на мой сервер. Я не уверен, как здесь может помочь прокси-маршрутизация. В любом случае все запросы уже проходят через мой сервер.

Stefan Falk 16.05.2018 10:09

Пользователь авторизовал мое приложение. Как работает ваша авторизация? Если вы нажимаете свой запрос oauth локальный: 8443 / вход / facebook .. после авторизации он возвращается на сервер. Где роль вашего углового веб-приложения? Разве не требуется авторизовать соединение между сетью а сервисный слой? Я только хочу знать, что такое промежуточный уровень вашего веб-приложения и сервисов angular.

this_is_om_vm 16.05.2018 11:31

Вы сами использовали Spring Social в одном из своих проектов?

Stefan Falk 16.05.2018 12:12

Дело в том, что я не вижу, что эта прокси-конфигурация делает для меня, за исключением экстернализации URL-адреса моего REST API - может быть, я здесь что-то не так? Однако, как указано в моем вопросе, я отправляю POST в https://localhost:8443/signin/facebook, который запускает магию Spring Social. Пользователь перенаправляется на страницу Facebook и авторизует мое приложение. Затем я получаю обратный вызов от Facebook и каким-то образом попадаю на https://localhost:8443/signup в моем браузере. Я либо делаю что-то совершенно не так, либо мне нужно что-то адаптировать из-за того, что веб-клиент и ..

Stefan Falk 16.05.2018 18:52

.. REST API находится в двух разных доменах. Эта «прокси-маршрутизация» больше похожа на причудливое название для экстернализации / централизации URL-адресов других конечных веб-точек?

Stefan Falk 16.05.2018 18:53

Это мой код PoC для signup, к вашему сведению

@Controller
class HomeController : AbstractController() {

  private var sessionStrategy: SessionStrategy = HttpSessionSessionStrategy()

  @Inject
  private lateinit var connectionFactoryLocator: ConnectionFactoryLocator

  @Inject
  private lateinit var usersConnectionRepository: FoodUsersConnectionRepository

  @RequestMapping("/")
  fun index(): String {
    logger.info("index")
    return "index"
  }

  @RequestMapping("/signup")
  fun signup(nativeWebRequest: NativeWebRequest) : String {
    sessionStrategy.getAttribute(nativeWebRequest , ProviderSignInAttempt.SESSION_ATTRIBUTE)
      .takeIf { it != null }
      .also { it ->
        val attempt = it as ProviderSignInAttempt
        val connection = attempt.getConnection(connectionFactoryLocator)
        logger.info("conn.key = {}" , connection.key)
        val user = userDao.save(User(RandomStringUtils.randomAlphanumeric(8) , RandomStringUtils.randomAlphanumeric(8)))
        val connRepo: ConnectionRepository = usersConnectionRepository.createConnectionRepository(user.id.toString())
        connRepo.addConnection(connection)
      }
    return "signup"
  }

}

Указывает на примечания:

Я получаю объект подключения, установленный в ProviderSignInController.handleSignIn(), он содержит свежую (не отображенную в db) пару providerId / providerUserId. И я создаю нового локального пользователя, даю ему случайную пару имени пользователя и пароля и связываю новый providerId / providerUserId с локальным пользователем.

Это простой PoC-код, его следует изменить в соответствии с вашей бизнес-логикой.

Может быть, вы можете отобразить форму, в которой пользователь сможет ввести свой ник, адрес или что-то в этом роде. Это зависит от вашей бизнес-логики.

Другие вопросы по теме