2013-08-13 14 views
5

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:

  1. Użyj niestandardowego filtru uwierzytelniającego z uwierzytelnianiemSupcessHandler. Oczywiście nie działa, ponieważ użytkownik jest już zalogowany w tym punkcie.
  2. Wykonaj implementację filtra punkt-punkt-ref.
  3. Wykonaj filtr niestandardowy w położeniu BASIC_AUTH_FILTER
  4. Wykonaj niestandardowego dostawcę uwierzytelnienia (bardzo długo się nie udaje!). Powtarzam to, a otrzymuję odpowiedzi.
  5. 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 { ... } 
+0

Wyślij swoje rozwiązanie jako odpowiedź, zamiast edytować swoje pytanie. ;) – bluish

Odpowiedz

3
  1. można zdefiniować niestandardowy filtr wstępnego uwierzytelniania przez rozszerzenie AbstractPreAuthenticatedProcessingFilter.
  2. W swojej implementacji metody getPreAuthenticatedPrincipal() można sprawdzić, czy plik cookie istnieje , a jeśli istnieje, zwracana nazwa pliku cookie jest podstawowa, a wartość pliku cookie - w poświadczeniach.
  3. Zastosowanie PreAuthenticatedAuthenticationProvider i podać swój własny preAuthenticatedUserDetailsService aby sprawdzić, czy plik cookie jest Vali, jeśli jego ważne również pobierające przyznane władze else rzucać AuthenticationException jak BadCredentialsException
  4. do uwierzytelniania użytkownika za pomocą nazwy użytkownika/hasła, dodać filtr form-login, podstawowy filtr lub filtr z niestandardowego dostawcy uwierzytelniania zwyczaj (lub niestandardowego userdetailsService) do sprawdzania poprawności użytkownika/hasło

w przypadku plików cookie istnieje, pre filtr auth ustawi uwierzytelniony użytkownik w springContext a filtr username./password nie zostanie wywołana, jeśli plik cookie jest nieprawidłowy/nieprawidłowy, punkt wejścia uwierzytelniającego uruchomi uwierzytelnianie za pomocą nazwy użytkownika/hasła

Mam nadzieję, że pomoże to

+0

Witam @ koder, wszystko ma sens. Spróbuję i opublikuję wyniki. Dzięki! – hectorg87

+1

@ hector87 możesz udostępnić swoją implementację i konfigurację? dzięki. –

+0

Tak, interesuje mnie również implementacja. Czy możesz gdzieś to zamieścić? Wielkie dzięki –

Powiązane problemy