Spring Social facebook + Spring Security

Я хочу интегрировать Facebook Spring Social в свое приложение с помощью Spring Security (я использую конфигурации xml). Все, что мне нужно, это просто подключить учетную запись facebook к учетной записи моего приложения. В простом примере я нашел это:

<bean id="connectionRepository" factory-method="createConnectionRepository" 
      factory-bean="usersConnectionRepository" scope="request">
    <constructor-arg value="#{request.userPrincipal.name}" />
    <aop:scoped-proxy proxy-target-class="false" />
</bean>

Итак, как я понял, в дело вступает такой метод:

public ConnectionRepository createConnectionRepository(String userId) {
        if (userId == null) {
            throw new IllegalArgumentException("userId cannot be null");
        }
        return new JdbcConnectionRepository(userId, jdbcTemplate, connectionFactoryLocator, textEncryptor, tablePrefix);
    }

Он извлекает "userId" из #{request.userPrincipal.name}. Итак, мой вопрос: как я могу передать «userId» этому методу, если я хочу получить это «userId», используя SecurityContextHolder.getContext().getAuthentication().getPrincipal().

Единственный способ, который я вижу, это создать свою реализацию JdbcUsersConnectionRepository и переопределить метод createConnectionRepository(String userId). Но, возможно, есть более элегантное решение.


person chaldaean    schedule 10.04.2013    source источник


Ответы (1)


Есть еще один способ:

<bean id="connectionRepository" factory-method="createConnectionRepository" factory-bean="usersConnectionRepository"
    scope="request">
    <constructor-arg value="#{authenticationService.getAuthenticatedUsername()}" />
    <aop:scoped-proxy proxy-target-class="false" />
</bean>

@Service("authenticationService")
public class AuthenticationService {

    public String getAuthenticatedUsername() {
        return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    }

}

Вы можете сделать это полностью и в SPeL (мне не нравятся такие зависимости):

<bean id="connectionRepository" factory-method="createConnectionRepository" factory-bean="usersConnectionRepository"
    scope="request">
    <constructor-arg value="#{T(org.springframework.security.core.context.SecurityContextHolder).getContext().getAuthentication().getPrincipal()}" />
    <aop:scoped-proxy proxy-target-class="false" />
</bean>
person Maksym Demidas    schedule 10.04.2013
comment
В Spring Social 1.0.x SpEL — лучший способ (хотя и немного громоздкий). В Spring Social 1.1.0 появилось новое пространство имен конфигурации на основе XML и интерфейс UserIdSource. Вы реализуете UserIdSource для поиска идентификатора пользователя (как вы считаете нужным) и настраиваете его как bean-компонент. Элементы конфигурации XML будут искать этот UserIdSource и использовать его. - person Craig Walls; 10.04.2013
comment
FWIW, тот факт, что выражения SpEL являются просто строками и, следовательно, не могут быть легко проверены или обязательно безопасны для типов, является основной причиной, по которой они здесь кажутся неуклюжими. Но в силу того, что вы выбираете XML для конфигурации, вы уже отказались от варианта конфигурации с безопасностью типов. Что заставило меня задуматься, почему вы не хотите использовать конфигурацию Java, которая является более мощным и типобезопасным вариантом для настройки Spring? - person Craig Walls; 10.04.2013
comment
Спасибо за разъяснения, Крейг. Интерфейс UserIdSource — хорошая новость (нам нужно дождаться версии 1.1.0.RELEASE, чтобы использовать его в рабочем коде). К вам второй вопрос: причина проста. У нас есть проект, в котором уже используется конфигурация на основе xml для Spring и Spring Security (структурные компоненты). Аннотации используются только для bean-компонентов приложения. Я думаю, что для службы поддержки будет удобнее иметь все настройки в одном формате (xml). Невозможно выполнить java conf с помощью Spring Security AFAIK. - person Maksym Demidas; 10.04.2013
comment
Спасибо @Maksym, ты мне очень помог. - person chaldaean; 11.04.2013
comment
Вы правы в том, что (пока) нет простого способа настроить Spring Security в JavaConfig. Тогда мой выбор по-прежнему состоял бы в том, чтобы выполнить как можно больше автоконфигурации (сканирование компонентов/автоматическое подключение), использовать JavaConfig как можно чаще для вещей, которые вы должны явно настроить, и использовать конфигурацию XML только в тех случаях, когда JavaConfig непрактично (например, Spring Security). Тем не менее, Spring Security 3.2.0.M1 имеет некоторую начальную поддержку JavaConfig, поэтому она появится в Spring Security 3.2.0. - person Craig Walls; 11.04.2013
comment
@Maksym, я использовал твое решение, но столкнулся с другой проблемой. SecurityContextHolder.getContext().getAuthentication() возвращает мне ноль. В других методах, где я использую SecurityContextHolder, все в порядке. Как я понял проблема кроется где-то в фильтрах безопасности. Если вы знаете, как это решить, я был бы признателен. - person chaldaean; 12.04.2013
comment
По умолчанию Spring Security создает анонимный сеанс для каждого анонимного пользователя. Может быть, эта функция отключена в вашем файле безопасности xml? Например, через ‹anonymous enabled=true /› - person Maksym Demidas; 12.04.2013
comment
Проблема в том, что мой пользователь не является анонимным. Я вхожу в свое приложение, прежде чем использовать getAuthenticatedUsername(). SecurityContextHolder.getContext().getAuthentication() возвращает null, только если я использую его в контексте метода getAuthenticatedUsername(). - person chaldaean; 12.04.2013
comment
Просто сделайте точку останова в методе SecurityContextImpl.setAuthentication(...) и найдите причину в режиме отладки. - person Maksym Demidas; 12.04.2013