Mam aplikację internetową SpringMVC, która musi uwierzytelnić się do usługi internetowej RESTful przy użyciu Spring Security, wysyłając nazwę użytkownika i hasło. Gdy użytkownik jest zalogowany, plik cookie musi zostać ustawiony na przeglądarkę użytkownika, a podczas kolejnych wywołań sesja użytkownika jest sprawdzana za pomocą innej usługi internetowej RESTful przy użyciu pliku cookie.Spring MVC + Spring Security zaloguj się z usługą internetową odpoczynku
Szukałem wszędzie, ale nie byłem w stanie znaleźć dobrego przykładu, jak to osiągnąć, a wszystkie moje próby poszły na marne.
Oto co mam na myśli:
mogę mieć dwa authentication-dostawców zadeklarowany, najpierw sprawdza plik cookie, a jeśli to się nie powiedzie z jakiegokolwiek powodu dojdzie do drugiego, który sprawdza za pomocą nazwy użytkownika i hasło (również się nie powiedzie, jeśli w tym żądaniu nie ma nazwy użytkownika i hasła).
Obie usługi zwracają władzę użytkownika za każdym razem, a bezpieczeństwo wiosenne jest "bezpaństwowe".
Z drugiej strony, zadałem sobie pytanie, czy to podejście jest poprawne, ponieważ tak trudno było znaleźć przykład lub kogoś innego z tym samym problemem. Czy to podejście jest złe?
Powodem, dla którego chcę to zrobić, a nie tylko uwierzytelnianie JDBC, jest to, że moja cała aplikacja internetowa jest bezstanowa, a baza danych jest zawsze dostępna za pośrednictwem usług internetowych RESTful, które obejmują "kolejkę petycji". Chciałbym uszanować to również w przypadku uwierzytelniania użytkownika i sprawdzania poprawności.
Co próbowałem do tej pory? Mogę wkleić długi long springSecurity-context.xml, ale zamiast tego wylistuję je na razie:
- Użyj niestandardowego filtru uwierzytelniającego z uwierzytelnianiemSupcessHandler. Oczywiście nie działa, ponieważ użytkownik jest już zalogowany w tym punkcie.
- Wykonaj implementację filtra punkt-punkt-ref.
- Wykonaj filtr niestandardowy w położeniu BASIC_AUTH_FILTER
- Wykonaj niestandardowego dostawcę uwierzytelnienia (bardzo długo się nie udaje!). Powtarzam to, a otrzymuję odpowiedzi.
- Zaczynałem używać CAS, gdy zdecydowałem się napisać pytanie. Być może w przyszłości będę mógł rozważyć posiadanie serwera CAS w mojej aplikacji internetowej, jednak w tej chwili wydaje się, że to ogromny przeskok.
Z góry dziękuję!
BTW, używam Spring Security 3.1.4 i Spring MVC 3.2.3
EDIT: Udało mi się to zrobić DZIĘKI @coder odpowiedź
Oto światło na to, co zrobiłem, postaram się udokumentować to wszystko i po to tutaj lub w blogu niedługo:
<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>
A niestandardowe implementacje są mniej więcej tak:
// 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 { ... }
Wyślij swoje rozwiązanie jako odpowiedź, zamiast edytować swoje pytanie. ;) – bluish