2013-12-14 10 views
14

Przeprowadzam eksperymenty z Spring 4 websockets and stomp i mam problem z ustaleniem/ustawieniem bieżącego użytkownika i innych atrybutów sesji w wiadomości metoda obsługi opisana za pomocą @MessageMapping.Jak zdobyć/ustawić atrybuty główne i sesyjne ze Spring 4 stomp websocket method

The documentation mówi, że metody obsługi komunikatów mogą przyjmować argument główny, a ja odkryłem, że główny jest pobierany przez Spring, wywołując getUserPrincipal() w macierzystej sesji gniazda, a następnie skojarzony z sesją gniazda, ale ja nie znalazłem sposób na łatwe dostosowanie tego zachowania, oprócz pisania filtra serwletów i zawijania oryginalnego żądania do opakowania zwracającego wartość główną znalezioną w moim pliku cookie.

Więc moje pytania to:

  1. Jak ręcznie ustawić kapitał do sesji gniazda, gdy klient łączy się (mam te informacje dzięki niestandardowym pliku cookie, a nie korzystają z zabezpieczeń Wiosny) ?
  2. Jeśli 1 nie jest możliwe, jak dodać dodatkowe atrybuty do sesji gniazda, gdy klient się połączy?
  3. Jak uzyskać dostęp do sesji gniazda i jego atrybutów za pomocą metody obsługi komunikatów?
  4. Czy istnieje sposób dostępu do loginu i hasła wysyłanego przez przeglądarkę w czasie połączenia. Wydaje się, że wiosną są całkowicie ignorowane i niedostępne.

Odpowiedz

5

AKTUALIZACJA: Z wiosną 4.1 możliwe jest ustawienie użytkownika na uścisku dłoni na # 1 z góry. Na the Spring documentation można utworzyć nową klasę, która rozszerza DefaultHandshakeHandler i zastępuje metodę determineUser. Dodatkowo możesz także utworzyć filtr bezpieczeństwa, który ustawia również mocodawcę, jeśli masz token. Zaimplementowałam drugi sam i dołączam kilka przykładowych kodów dla obu poniżej.

Dla nr 2 i nr 3 nie sądzę, że jest to możliwe. Dla nr 4 Spring celowo ignoruje te wartości na the documentation here.

przykład kodu DefaultHandshakeHandler podklasy: KOD

@Configuration 
@EnableWebSocketMessageBroker 
public class ApplicationWebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer { 

    public class MyHandshakeHandler extends DefaultHandshakeHandler { 

     @Override 
     protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, 
              Map<String, Object> attributes) { 
      // add your own code to determine the user 
      return null; 
     } 
    } 

    @Override 
    public void registerStompEndpoints(StompEndpointRegistry registry) { 

     registry.addEndpoint("/myEndPoint").setHandshakeHandler(new MyHandshakeHandler()); 

    } 
} 

SAMPLE filtra Bezpieczeństwo:

public class ApplicationSecurityTokenFilter extends GenericFilterBean { 

    private final static String AUTHENTICATION_PARAMETER = "authentication"; 

    @Override 
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 
     if (servletRequest instanceof HttpServletRequest) { 
      // check to see if already authenticated before trying again 
      Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication(); 
      if ((existingAuth == null) || !existingAuth.isAuthenticated()) { 
       HttpServletRequest request = (HttpServletRequest)servletRequest; 
       UsernamePasswordAuthenticationToken token = extractToken(request); 
       // dump token into security context (for authentication-provider to pick up) 
       if (token != null) { // if it exists 
        SecurityContextHolder.getContext().setAuthentication(token); 
       } 
      } 
     } 
     filterChain.doFilter(servletRequest,servletResponse); 
    } 

    private UsernamePasswordAuthenticationToken extractToken(HttpServletRequest request) { 
     UsernamePasswordAuthenticationToken authenticationToken = null; 
     // do what you need to extract the information for a token 
     // in this example we assume a query string that has an authenticate 
     // parameter with a "user:password" string. A new UsernamePasswordAuthenticationToken 
     // is created and then normal authentication happens using this info. 
     // This is just a sample and I am sure there are more secure ways to do this. 
     if (request.getQueryString() != null) { 
      String[] pairs = request.getQueryString().split("&"); 
      for (String pair : pairs) { 
       String[] pairTokens = pair.split("="); 
       if (pairTokens.length == 2) { 
        if (AUTHENTICATION_PARAMETER.equals(pairTokens[0])) { 
         String[] tokens = pairTokens[1].split(":"); 
         if (tokens.length == 2) { 
          log.debug("Using credentials: " + pairTokens[1]); 
          authenticationToken = new UsernamePasswordAuthenticationToken(tokens[0], tokens[1]); 
         } 
        } 
       } 
      } 
     } 
     return authenticationToken; 
    } 
} 

// set up your web security for the area in question 
@Configuration 
public class SubscriptionWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 

    protected void configure(HttpSecurity http) throws Exception { 
     http 
       .requestMatchers().antMatchers("/myEndPoint**","/myEndPoint/**").and() 
       .addFilterBefore(new ApplicationSecurityTokenFilter(), UsernamePasswordAuthenticationFilter.class) 
       .authorizeRequests() 
       .anyRequest().authenticated() 
       .and() 
       .httpBasic() // leave this if you want non web browser clients to connect and add an auth header 
       .and() 
       .csrf().disable(); 
    } 
} 

** UWAGA: ** nie deklaruje swój filtr jako Bean. Jeśli to zrobisz, zostanie również pobrane (przynajmniej przy użyciu Spring Boot) w filtrach generycznych, więc będzie uruchamiane przy każdym żądaniu.

Powiązane problemy