У меня есть веб-приложение SpringMVC, которому необходимо пройти аутентификацию в веб-службе RESTful с помощью Spring Security, отправив имя пользователя и пароль. Когда пользователь входит в систему, файл cookie должен быть установлен в браузере пользователя, а при последующих вызовах сеанс пользователя проверяется с помощью другой веб-службы RESTful с использованием файла cookie.
Я искал везде, но не смог найти хороший пример того, как это сделать, и все мои попытки были тщетны.
Вот что я имею в виду:
Я могу объявить двух провайдеров аутентификации, первый проверяет файл cookie, и если он по какой-либо причине не работает, он переходит ко второму, который проверяет имя пользователя и пароль (также произойдет сбой, если в этом запросе нет имени пользователя и пароля) .
Оба сервиса каждый раз возвращают полномочия пользователя, а spring безопасность "без гражданства".
С другой стороны, я задавался вопросом, верен ли этот подход, поскольку было очень трудно найти пример или кого-то другого с такой же проблемой. Является ли этот подход неправильным?
Причина, по которой я хочу сделать это вместо простой аутентификации JDBC, заключается в том, что все мое веб-приложение не имеет состояния, а доступ к базе данных всегда осуществляется через веб-службы RESTful, которые обертывают «очередь петиций», я хотел бы уважать это для аутентификации пользователя и проверка тоже.
Что я пробовал до сих пор? Я мог бы вставить длинный файл springSecurity-context.xml, но пока просто перечислю их:
- Используйте настраиваемый фильтр аутентификации с обработчиком authenticationSuccessHandler. Очевидно, не работает, потому что пользователь уже вошел в систему в этой точке.
- Сделайте реализацию фильтра входной точки-ссылки.
- Сделайте пользовательский фильтр в позиции BASIC_AUTH_FILTER
- Создайте собственный поставщик аутентификации (много боролся, но безуспешно!). Я повторяю это, пока получаю ответы.
- Я начал использовать 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 { ... }