Вход в Spring MVC + Spring Security с веб-службой отдыха

У меня есть веб-приложение SpringMVC, которому необходимо пройти аутентификацию в веб-службе RESTful с помощью Spring Security, отправив имя пользователя и пароль. Когда пользователь входит в систему, файл cookie должен быть установлен в браузере пользователя, а при последующих вызовах сеанс пользователя проверяется с помощью другой веб-службы RESTful с использованием файла cookie.

Я искал везде, но не смог найти хороший пример того, как это сделать, и все мои попытки были тщетны.

Вот что я имею в виду:

Я могу объявить двух провайдеров аутентификации, первый проверяет файл cookie, и если он по какой-либо причине не работает, он переходит ко второму, который проверяет имя пользователя и пароль (также произойдет сбой, если в этом запросе нет имени пользователя и пароля) .

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

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

Причина, по которой я хочу сделать это вместо простой аутентификации JDBC, заключается в том, что все мое веб-приложение не имеет состояния, а доступ к базе данных всегда осуществляется через веб-службы RESTful, которые обертывают «очередь петиций», я хотел бы уважать это для аутентификации пользователя и проверка тоже.

Что я пробовал до сих пор? Я мог бы вставить длинный файл springSecurity-context.xml, но пока просто перечислю их:

  1. Используйте настраиваемый фильтр аутентификации с обработчиком authenticationSuccessHandler. Очевидно, не работает, потому что пользователь уже вошел в систему в этой точке.
  2. Сделайте реализацию фильтра входной точки-ссылки.
  3. Сделайте пользовательский фильтр в позиции BASIC_AUTH_FILTER
  4. Создайте собственный поставщик аутентификации (много боролся, но безуспешно!). Я повторяю это, пока получаю ответы.
  5. Я начал использовать CAS, когда вместо этого решил написать вопрос. Возможно, в будущем я смогу рассмотреть возможность использования сервера CAS в своем веб-приложении, однако на данный момент это кажется огромным излишеством.

Заранее спасибо!

Кстати, я использую Spring Security 3.1.4 и Spring MVC 3.2.3.

РЕДАКТИРОВАТЬ: Я СМОГ СДЕЛАТЬ ЭТО БЛАГОДАРЯ ОТВЕТУ @coder

Вот кое-что о том, что я сделал, я постараюсь задокументировать все это и опубликовать здесь или в блоге в ближайшее время:

<http use-expressions="true" create-session="stateless" entry-point-ref="loginUrlAuthenticationEntryPoint"
        authentication-manager-ref="customAuthenticationManager">
    <custom-filter ref="restAuthenticationFilter" position="FORM_LOGIN_FILTER" />
    <custom-filter ref="restPreAuthFilter" position="PRE_AUTH_FILTER" />
    <intercept-url pattern="/signin/**" access="permitAll" />
    <intercept-url pattern="/img/**" access="permitAll" />
    <intercept-url pattern="/css/**" access="permitAll" />
    <intercept-url pattern="/js/**" access="permitAll" />
    <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />

</http>

<authentication-manager id="authManager" alias="authManager">
    <authentication-provider ref="preauthAuthProvider" />
</authentication-manager>

<beans:bean id="restPreAuthFilter" class="com.company.CustomPreAuthenticatedFilter">
    <beans:property name="cookieName" value="SessionCookie" />
    <beans:property name="checkForPrincipalChanges" value="true" />
    <beans:property name="authenticationManager" ref="authManager" />
</beans:bean>

<beans:bean id="preauthAuthProvider"
    class="com.company.CustomPreAuthProvider">
    <beans:property name="preAuthenticatedUserDetailsService">
        <beans:bean id="userDetailsServiceWrapper"
            class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
            <beans:property name="userDetailsService" ref="userDetailsService" />
        </beans:bean>
    </beans:property>
</beans:bean>

<beans:bean id="userDetailsService" class="com.company.CustomUserDetailsService" />

<beans:bean id="loginUrlAuthenticationEntryPoint"
    class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
    <beans:constructor-arg value="/signin" />
</beans:bean>

<beans:bean id="customAuthenticationManager"
    class="com.company.CustomAuthenticationManager" />

<beans:bean id="restAuthenticationFilter"
    class="com.company.CustomFormLoginFilter">
    <beans:property name="filterProcessesUrl" value="/signin/authenticate" />
    <beans:property name="authenticationManager" ref="customAuthenticationManager" />
    <beans:property name="authenticationFailureHandler">
        <beans:bean
            class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
            <beans:property name="defaultFailureUrl" value="/login?login_error=t" />
        </beans:bean>
    </beans:property>
</beans:bean>

И пользовательские реализации выглядят примерно так:

// Here, the idea is to write authenticate method and return a new UsernamePasswordAuthenticationToken
public class CustomAuthenticationManager implements AuthenticationManager { ... }

// Write attemptAuthentication method and return UsernamePasswordAuthenticationToken 
public class CustomFormLoginFilter extends UsernamePasswordAuthenticationFilter { ... }

// Write getPreAuthenticatedPrincipal and getPreAuthenticatedCredentials methods and return cookieName and cookieValue respectively
public class CustomPreAuthenticatedFilter extends AbstractPreAuthenticatedProcessingFilter { ... }

// Write authenticate method and return Authentication auth = new UsernamePasswordAuthenticationToken(name, token, grantedAuths); (or null if can't be pre-authenticated)
public class CustomPreAuthProvider extends PreAuthenticatedAuthenticationProvider{ ... }

// Write loadUserByUsername method and return a new UserDetails user = new User("hectorg87", "123456", Collections.singletonList(new GrantedAuthorityImpl("ROLE_USER")));
public class CustomUserDetailsService implements UserDetailsService { ... }

person hectorg87    schedule 13.08.2013    source источник
comment
Опубликуйте свое решение в качестве ответа, пожалуйста, вместо того, чтобы редактировать свой вопрос. ;)   -  person bluish    schedule 09.01.2015


Ответы (1)


  1. вы можете определить собственный фильтр предварительной аутентификации, расширив AbstractPreAuthenticatedProcessingFilter.
  2. В вашей реализации метода getPreAuthenticatedPrincipal() вы можете проверить, существует ли файл cookie, и если он существует, имя файла cookie возврата является основным, а значение файла cookie в учетных данных.
  3. Используйте PreAuthenticatedAuthenticationProvider и предоставьте свой собственный preAuthenticatedUserDetailsService, чтобы проверить, является ли файл cookie действительным, если он действителен, также извлеките предоставленные полномочия, иначе выдайте AuthenticationException, например BadCredentialsException
  4. Для аутентификации пользователя с использованием имени пользователя/пароля добавьте фильтр формы входа, базовый фильтр или настраиваемый фильтр с настраиваемым поставщиком аутентификации (или настраиваемым сервисом userdetailsService) для проверки пользователя/пароля.

Если файл cookie существует, фильтр предварительной аутентификации установит аутентифицированного пользователя в springContext, и фильтр вашего имени пользователя/пароля не будет вызываться, если файл cookie ошибочен/недействителен, точка входа аутентификации вызовет аутентификацию с использованием имени пользователя/пароля.

Надеюсь, поможет

person coder    schedule 13.08.2013
comment
Привет @coder, все это имеет смысл. Я попробую и отпишусь о результатах. Спасибо! - person hectorg87; 13.08.2013
comment
@ hector87, можете ли вы поделиться своей реализацией и конфигурацией? благодаря. - person Jorge Infante Osorio; 25.03.2014
comment
Да, меня тоже интересует реализация. Не могли бы вы выложить его где-нибудь? Большое спасибо - person Jonathan Lebrun; 16.07.2014
comment
@ hectorg87, не могли бы вы поделиться ссылками на блог, если вы их опубликовали. Я пытаюсь аутентифицировать FB SignIn в приложении Spring на основе REST. в настоящее время я настроил безопасность с пользовательским AuthenticationEntryPoint и пользовательским SimpleUrlAuthenticationSuccessHandler и диспетчером аутентификации с пользовательским userLoginService, который получает учетные данные пользователя из db. я не уверен, как добавлять/управлять фильтрами PreAuth с моей существующей конфигурацией, поскольку PreAuthenticatedAuthenticationProvider требует preAuthenticatedUserDetailsService, я не уверен, нужно ли заменить мой userDetailService. - person alphabytes; 10.12.2014