2015-07-01 98 views
1

我試圖用簡單的代理,SockJS和STOMP來實現Spring Websocket。我的應用程序在擴展HandlerInterceptorAdapter類的自定義攔截器(稱爲SecurityInterceptor)中處理認證。 我想要建立連接時通過SOMP客戶端發出的HTTP請求,以通過我的攔截器類,以便驗證用戶是經過身份驗證的用戶。但是,這些初始HTTP請求不會通過我的自定義攔截器。請問有人能夠在這個問題上給我啓發嗎?以下是我在做什麼如何通過HandlerInterceptorAdapter連接到WebSocket

主要web配置班組長:

@Configuration 
    @EnableWebMvc 
    @ComponentScan({ "..." }) 
    public class RestWebSvcMainConfig extends WebMvcConfigurerAdapter { 

     public void addInterceptors(final InterceptorRegistry oRegistry) { 

      try { 

       oRegistry.addInterceptor(securityInterceptor()).addPathPatterns("/dms/secured/**"); 
      } 
      catch (Exception ex) { 

       throw new RuntimeException(ex); 
      } 
     } 

     @Bean 
     public SecurityInterceptor securityInterceptor() throws Exception { 
      SecurityInterceptor oSecurityInterceptor = new SecurityInterceptor(authenticationProvider()); 
      return oSecurityInterceptor; 
     } 

    } 

的WebSocket配置類:

@Configuration 
@ComponentScan({"..."}) 
@EnableWebSocketMessageBroker 
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { 

    @Override 
    public void configureMessageBroker(MessageBrokerRegistry config) { 
     config.enableSimpleBroker("/topic"); 
     config.setApplicationDestinationPrefixes("/app"); 
    } 

    public void registerStompEndpoints(StompEndpointRegistry registry) { 
     registry.addEndpoint("/dms/secured/hello").withSockJS(); 
    } 

} 

控制器類:

@Controller 
public class GreetingController { 
    @MessageMapping("/dms/secured/hello") 
    @SendToUser(value="/topic/greetings", broadcast = false) 
    public Greeting greeting(HelloMessage message) throws Exception { 
     Thread.sleep(3000); // simulated delay 
     return new Greeting("Hello, " + message.getName() + "!"); 
    } 

} 

分發程序Servlet的Web製圖.xml:

<!-- Map all requests to the dispatcher servlet --> 
<servlet-mapping> 
    <servlet-name>dispatcher</servlet-name> 
    <url-pattern>/</url-pattern> 
</servlet-mapping> 

STOMP客戶端:

function connect() { 
    var socket = new SockJS('/GlobalAPI/dms/secured/hello'); 
    stompClient = Stomp.over(socket); 
    stompClient.connect({}, function(frame) { 
    setConnected(true); 
    console.log('Connected: ' + frame); 
    stompClient.subscribe('/user/topic/greetings', function(greeting){ 
     showGreeting(JSON.parse(greeting.body).content); 
    }); 
    }); 
} 

GlobalAPI是上下文根。

最初的請求是http://localhost:8080/GlobalAPI/dms/secured/hello/info沒有經過攔截器。當我做出任何其他HTTP請求,如http://localhost:8080/GlobalAPI/dms/secured/documents,請求很好地徹底攔截器。 我的代碼有什麼問題?

+0

爲什麼要這樣。該請求不是由處理程序處理的,因此「HandlerInterceptor」不適用。爲了攔截Web套接字連接,你可能需要使用'HandshakeInterceptor'。 –

回答

0

我推薦你實現你自己的HandshakeInterceptor實現。我複製一個實現Spring框架的所有代碼:

package mx.config.ws; 

import java.util.Collection; 
import java.util.Collections; 
import java.util.Enumeration; 
import java.util.Map; 

import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpSession; 

import org.springframework.http.server.ServerHttpRequest; 
import org.springframework.http.server.ServerHttpResponse; 
import org.springframework.http.server.ServletServerHttpRequest; 
import org.springframework.web.socket.WebSocketHandler; 
import org.springframework.web.socket.server.HandshakeInterceptor; 

public class HttpSessionHandshakeInterceptor_personalised implements HandshakeInterceptor { 


    /** 
    * The name of the attribute under which the HTTP session id is exposed when 
    * {@link #setCopyHttpSessionId(boolean) copyHttpSessionId} is "true". 
    */ 
    public static final String HTTP_SESSION_ID_ATTR_NAME = "HTTP.SESSION.ID"; 


    private final Collection<String> attributeNames; 

    private boolean copyAllAttributes; 

    private boolean copyHttpSessionId = true; 

    private boolean createSession; 


    /** 
    * Default constructor for copying all HTTP session attributes and the HTTP 
    * session id. 
    * @see #setCopyAllAttributes 
    * @see #setCopyHttpSessionId 
    */ 
    public HttpSessionHandshakeInterceptor_personalised() { 
     this.attributeNames = Collections.emptyList(); 
     this.copyAllAttributes = true; 
    } 

    /** 
    * Constructor for copying specific HTTP session attributes and the HTTP 
    * session id. 
    * @param attributeNames session attributes to copy 
    * @see #setCopyAllAttributes 
    * @see #setCopyHttpSessionId 
    */ 
    public HttpSessionHandshakeInterceptor_personalised(Collection<String> attributeNames) { 
     this.attributeNames = Collections.unmodifiableCollection(attributeNames); 
     this.copyAllAttributes = false; 
    } 


    /** 
    * Return the configured attribute names to copy (read-only). 
    */ 
    public Collection<String> getAttributeNames() { 
     return this.attributeNames; 
    } 

    /** 
    * Whether to copy all attributes from the HTTP session. If set to "true", 
    * any explicitly configured attribute names are ignored. 
    * <p>By default this is set to either "true" or "false" depending on which 
    * constructor was used (default or with attribute names respectively). 
    * @param copyAllAttributes whether to copy all attributes 
    */ 
    public void setCopyAllAttributes(boolean copyAllAttributes) { 
     this.copyAllAttributes = copyAllAttributes; 
    } 

    /** 
    * Whether to copy all HTTP session attributes. 
    */ 
    public boolean isCopyAllAttributes() { 
     return this.copyAllAttributes; 
    } 

    /** 
    * Whether the HTTP session id should be copied to the handshake attributes 
    * under the key {@link #HTTP_SESSION_ID_ATTR_NAME}. 
    * <p>By default this is "true". 
    * @param copyHttpSessionId whether to copy the HTTP session id. 
    */ 
    public void setCopyHttpSessionId(boolean copyHttpSessionId) { 
     this.copyHttpSessionId = copyHttpSessionId; 
    } 

    /** 
    * Whether to copy the HTTP session id to the handshake attributes. 
    */ 
    public boolean isCopyHttpSessionId() { 
     return this.copyHttpSessionId; 
    } 

    /** 
    * Whether to allow the HTTP session to be created while accessing it. 
    * <p>By default set to {@code false}. 
    * @see javax.servlet.http.HttpServletRequest#getSession(boolean) 
    */ 
    public void setCreateSession(boolean createSession) { 
     this.createSession = createSession; 
    } 

    /** 
    * Whether the HTTP session is allowed to be created. 
    */ 
    public boolean isCreateSession() { 
     return this.createSession; 
    } 


    @Override 
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, 
      WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { 


     // Set ip attribute to WebSocket session 
     attributes.put("ip", request.getRemoteAddress()); 

     // ============================================= CODIGO PERSONAL 
     ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request; 
     HttpServletRequest httpServletRequest = servletRequest.getServletRequest(); 
//  httpServletRequest.getCookies(); 
//  httpServletRequest.getParameter("inquiryId"); 
//  httpServletRequest.getRemoteUser(); 



     System.out.println("SessionHandshakeInterceptor::beforeHandshake() httpServletRequest.getRemoteUser()(): "+httpServletRequest.getRemoteUser()); 

     // Salida:  "/127.0.0.1:8080" 
     System.out.println("SessionHandshakeInterceptor::beforeHandshake() request.getLocalAddress(): "+request.getLocalAddress()); 
     // Salida:  "http://localhost:8080/ServLocalBancarias-0.0.1-SNAPSHOT/chat/923/uezxomjg/websocket" 
     System.out.println("SessionHandshakeInterceptor::beforeHandshake() request.getURI(): "+request.getURI()); 
     // Salida:  "/127.0.0.1:59197" 
     System.out.println("SessionHandshakeInterceptor::beforeHandshake() request.getRemoteAddress(): "+request.getRemoteAddress()); 
     // Salida: null 
     System.out.println("SessionHandshakeInterceptor::beforeHandshake() request.getPrincipal(): "+request.getPrincipal()); 
     /* 
     * { 
       Origin=[http://localhost:3000], 
       Cookie=[__utma=111872281.293045146.1470257629.1470257649.1470362764.31; 
       __utmc=111872281; 
       __utmz=111872281.1470257629.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)], 
       Sec-WebSocket-Key=[XGDdYK2TDz6djy852SzBNg==], 
       User-Agent=[Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36], 
       Connection=[Upgrade], 
       Sec-WebSocket-Version=[13], 
       Host=[localhost:8080], 
       Accept-Encoding=[gzip, deflate, sdch], 
       DNT=[1], 
       Pragma=[no-cache], 
       Upgrade=[websocket], 
       Sec-WebSocket-Extensions=[permessage-deflate; 
       client_max_window_bits], 
       Cache-Control=[no-cache], 
       Accept-Language=[en-US,en;q=0.8] 
      } 

     */ 
     System.out.println("SessionHandshakeInterceptor::beforeHandshake() request.getHeaders(): "+request.getHeaders()); 

     /* 
     * Salida: 
     */ 
     attributes.forEach((key,value)->{System.out.println("SessionHandshakeInterceptor::beforeHandshake() attributes Key: "+key+" Value: "+value);}); 








     // ============================================== CODIGO ORIGINAL DE Spring INI 
     HttpSession session = getSession(request); 
     if (session != null) { 

      // ===================================== INI 

      System.out.println("SessionHandshakeInterceptor::beforeHandshake() session: "+session); 


      // ===================================== END 


      if (isCopyHttpSessionId()) { 
       attributes.put(HTTP_SESSION_ID_ATTR_NAME, session.getId()); 
      } 
      Enumeration<String> names = session.getAttributeNames(); 
      while (names.hasMoreElements()) { 
       String name = names.nextElement(); 
       if (isCopyAllAttributes() || getAttributeNames().contains(name)) { 
        attributes.put(name, session.getAttribute(name)); 
       } 
      } 
     } 
     // ============================================== CODIGO ORIGINAL DE Spring END 



     return true; 
    } 

    private HttpSession getSession(ServerHttpRequest request) { 
     if (request instanceof ServletServerHttpRequest) { 
      ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) request; 
      return serverRequest.getServletRequest().getSession(isCreateSession()); 
     } 
     return null; 
    } 

    @Override 
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, 
      WebSocketHandler wsHandler, Exception ex) { 

     System.out.println("SessionHandshakeInterceptor::afterHandshake()"); 

    } 


} 

接下來,你需要創建一個bean:

@EnableScheduling 
@Configuration 
@EnableWebSocketMessageBroker 
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { 

    @Bean 
    public HttpSessionHandshakeInterceptor_personalised handShakeInterceptor() { 
     return new HttpSessionHandshakeInterceptor_personalised(); 
    } 

Override 
    public void registerStompEndpoints(StompEndpointRegistry registry) { 
     //registry.addEndpoint("/ws").withSockJS(); 

     // Enpoint para el chat de pruebas. 
     registry.addEndpoint("/chat") 
//   .addInterceptors(new IpHandshakeInterceptor()) 
//   .addInterceptors(new SessionHandshakeInterceptor())// FUNCIONA TAMBIEN, IGUAL QUE EL OTRO 
//   .addInterceptors(new HttpSessionHandshakeInterceptor()) 
      .addInterceptors(handShakeInterceptor()) // Este el mejor y unico necesario. 
//   .setHandshakeHandler(handshakeHandler) 
      .setAllowedOrigins("*")  // ELIMINAR. USADO PARA PERMITIR CONECTARSE DESDE OTRO SERVIDOR TIPO LOCALHOST 
      .withSockJS() 
      ;  


    } 
    ... 
} 

這爲我工作。