2015-05-04 16 views
15

Lưu ý: xem cập nhật ở cuối câu hỏi cho những gì tôi cuối cùng đã kết luận.Trả lời nhiều lần trên web-socket mà không cần xác thực mùa xuân

Tôi cần gửi nhiều câu trả lời tới yêu cầu qua ổ cắm web đã gửi thông báo yêu cầu, thư đầu tiên nhanh chóng và các thư khác sau khi dữ liệu được xác minh (khoảng 10 đến 60 giây sau, từ nhiều luồng song song) .

Tôi gặp sự cố khi nhận phản hồi sau để ngừng phát trên tất cả các ổ cắm web mở. Làm cách nào để tôi chỉ gửi chúng tới ổ cắm web ban đầu? Hoặc tôi nên sử dụng cái gì đó ngoài Spring STOMP (bởi vì, thành thật mà nói, tất cả những gì tôi muốn là thông điệp định tuyến đến các chức năng khác nhau, tôi không cần hoặc muốn khả năng phát tới các ổ cắm web khác, vì vậy tôi nghi ngờ mình có thể viết tin nhắn phân phối bản thân mình, mặc dù nó đang tái phát minh bánh xe).

Tôi không sử dụng Xác thực mùa xuân (điều này đang được trang bị thêm vào mã cũ).

Trên thư trả lại ban đầu, tôi có thể sử dụng @SendToUser và mặc dù chúng tôi không có người dùng, Spring chỉ gửi giá trị trả về tới websocket gửi thư. (xem this question).

Với các phản hồi chậm hơn, tôi nghĩ rằng tôi cần sử dụng SimpMessagingTemplate.convertAndSendToUser (người dùng, đích, thư), nhưng tôi không thể, vì tôi phải chuyển người dùng và không thể tìm ra người dùng @SendToUser đã sử dụng cái gì. Tôi đã cố gắng làm theo các bước in this question, nhưng không nhận được nó để làm việc khi không được xác thực (principal.getName() trả về null trong trường hợp này).

Tôi đã đơn giản hóa điều này đáng kể cho mẫu thử nghiệm, vì vậy đừng lo lắng về việc đồng bộ hóa chủ đề hoặc bất kỳ thứ gì. Tôi chỉ muốn các ổ cắm web hoạt động chính xác.

Đây là bộ điều khiển của tôi:

@Controller 
public class TestSocketController 
{ 
    private SimpMessagingTemplate template; 

    @Autowired 
    public TestSocketController(SimpMessagingTemplate template) 
    { 
    this.template = template; 
    } 

    // This doesn't work because I need to pass something for the first parameter. 
    // If I just use convertAndSend, it broacasts the response to all browsers 
    void setResults(String ret) 
    { 
    template.convertAndSendToUser("", "/user/topic/testwsresponse", ret); 
    } 

    // this only sends "Testing Return" to the browser tab hooked to this websocket 
    @MessageMapping(value="/testws") 
    @SendToUser("/topic/testwsresponse") 
    public String handleTestWS(String msg) throws InterruptedException 
    { 
    (new Thread(new Later(this))).start(); 
    return "Testing Return"; 
    } 

    public class Later implements Runnable 
    { 
    TestSocketController Controller; 
    public Later(TestSocketController controller) 
    { 
     Controller = controller; 
    } 

    public void run() 
    { 
     try 
     { 
      java.lang.Thread.sleep(2000); 

      Controller.setResults("Testing Later Return"); 
     } 
     catch (Exception e) 
     { 
     } 
    } 
    } 
} 

Đối với hồ sơ, đây là mặt trình duyệt:

var client = null; 
function sendMessage() 
{ 
    client.send('/app/testws', {}, 'Test'); 
} 

// hooked to a button 
function test() 
{ 
    if (client != null) 
    { 
     sendMessage(); 
     return; 
    } 

    var socket = new SockJS('/application-name/sendws/'); 
    client = Stomp.over(socket); 
    client.connect({}, function(frame) 
    { 
     client.subscribe('/user/topic/testwsresponse', function(message) 
     { 
      alert(message); 
     }); 

     sendMessage(); 
    }); 
}); 

Và đây là cấu hình:

@Configuration 
@EnableWebSocketMessageBroker 
public class TestSocketConfig extends AbstractWebSocketMessageBrokerConfigurer 
{ 
    @Override 
    public void configureMessageBroker(MessageBrokerRegistry config) 
    { 
     config.setApplicationDestinationPrefixes("/app"); 
     config.enableSimpleBroker("/queue", "/topic"); 
     config.setUserDestinationPrefix("/user"); 
    } 

    @Override 
    public void registerStompEndpoints(StompEndpointRegistry registry) 
    { 
     registry.addEndpoint("/sendws").withSockJS(); 
    } 
} 

UPDATE: Do các vấn đề bảo mật liên quan đến khả năng thông tin được gửi qua các ổ cắm web khác so với ổ cắm gốc , Tôi đã kết thúc đề xuất với nhóm của mình rằng chúng tôi không sử dụng triển khai Spring 4.0 của STOMP trên Web Sockets. Tôi hiểu tại sao nhóm Spring đã làm theo cách họ đã làm, và nó là sức mạnh nhiều hơn thì chúng tôi cần, nhưng những hạn chế về bảo mật đối với dự án của chúng tôi là đủ nghiêm trọng, và các yêu cầu thực tế đủ đơn giản, chúng tôi quyết định đi theo một cách khác . Điều đó không làm mất hiệu lực các câu trả lời dưới đây, vì vậy hãy đưa ra quyết định của riêng bạn dựa trên nhu cầu của dự án của bạn. Ít nhất chúng tôi hy vọng tất cả đã học được những hạn chế của công nghệ, cho tốt hay xấu.

Trả lời

6

Tại sao bạn không sử dụng một chủ đề riêng biệt cho từng khách hàng?

  1. Khách hàng tạo id phiên.

    var sessionId = Math.random().toString(36).substring(7);

  2. Khách hàng đặt mua/chủ đề/testwsresponse/{sessionId}, sau đó gửi một thông điệp tới '/ app/testws/{sessionId}'.

  3. Trong bộ điều khiển của bạn, bạn sử dụng @MessageMapping (value = "/ testws/{sessionId}") và xóa @SendToUser. Bạn có thể sử dụng @DestinationVariable để truy cập sessionId trong phương thức của bạn.
  4. Bộ điều khiển gửi thêm phản hồi tới/topic/testwsresponse/{sessionId}.

Bản chất Mùa xuân thực hiện điều tương tự khi bạn sử dụng điểm đến của người dùng. Vì bạn không sử dụng Xác thực mùa xuân, bạn không thể dựa vào cơ chế này nhưng bạn có thể dễ dàng triển khai thực hiện của riêng mình như tôi đã mô tả ở trên.

var client = null; 
var sessionId = Math.random().toString(36).substring(7); 
function sendMessage() 
{ 
    client.send('/app/testws/' + sessionId, {}, 'Test'); 
} 

// hooked to a button 
function test() 
{ 
    if (client != null) 
    { 
     sendMessage(); 
     return; 
    } 

    var socket = new SockJS('/application-name/sendws/'); 
    client = Stomp.over(socket); 
    client.connect({}, function(frame) 
    { 
     client.subscribe('/topic/testwsresponse/' + sessionId, function(message) 
     { 
      alert(message); 
     }); 

     // Need to wait until subscription is complete 
     setTimeout(sendMessage, 1000); 
    }); 
}); 

Bộ điều khiển:

@Controller 
public class TestSocketController 
{ 
    private SimpMessagingTemplate template; 

    @Autowired 
    public TestSocketController(SimpMessagingTemplate template) 
    { 
     this.template = template; 
    } 

    void setResults(String ret, String sessionId) 
    { 
     template.convertAndSend("/topic/testwsresponse/" + sessionId, ret); 
    } 

    @MessageMapping(value="/testws/{sessionId}") 
    public void handleTestWS(@DestinationVariable String sessionId, @Payload String msg) throws InterruptedException 
    { 
     (new Thread(new Later(this, sessionId))).start(); 
     setResults("Testing Return", sessionId); 
    } 

    public class Later implements Runnable 
    { 
     TestSocketController Controller; 
     String sessionId; 
     public Later(TestSocketController controller, String sessionId) 
     { 
      Controller = controller; 
      this.sessionId = sessionId; 
     } 

     public void run() 
     { 
      try 
      { 
       java.lang.Thread.sleep(2000); 

       Controller.setResults("Testing Later Return", sessionId); 
      } 
      catch (Exception e) 
      { 
      } 
     } 
    } 
} 

Chỉ cần kiểm tra nó, làm việc như mong đợi.

+0

Tôi có một vài vấn đề về bảo mật với điều này. Đầu tiên là ai đó có thể tìm ra chuỗi ký tự ngẫu nhiên mà người khác đang sử dụng và nghe cuộc trò chuyện. Thứ hai là ai đó có thể đăng ký một số (hoặc tất cả, có thể) các chuỗi tiềm năng và lắng nghe tất cả các câu trả lời. Ngay cả nhận được may mắn và lắng nghe một người khác phản ứng là không đủ an toàn cho dự án này. Tôi thực sự cần phải chỉ gửi tin nhắn qua một ổ cắm web duy nhất, và tôi bắt đầu nghĩ rằng việc triển khai Spring của STOMP sẽ không làm điều đó .. –

+0

Bạn không nên lo lắng về vấn đề bảo mật. Chỉ cần sử dụng chuỗi ngẫu nhiên đủ dài hoặc sử dụng UUID cho id phiên. http://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates Về cơ bản, hacker sẽ cần 17 tỷ năm để phá vỡ hệ thống của bạn. – medvedev1088

+0

Có nhiều khả năng tôi đoán mật khẩu gmail của bạn hơn là hacker sẽ đoán id phiên ngẫu nhiên. – medvedev1088

0

Đây không phải là câu trả lời đầy đủ. Chỉ cần xem xét chung và gợi ý. Bạn không thể thực hiện các công cụ hoặc loại kết nối khác nhau thông qua cùng một ổ cắm. Tại sao không có ổ cắm khác nhau cho công việc khác nhau? Một số có xác thực và một số không có. Một số cho nhiệm vụ nhanh chóng và một số cho thực hiện lâu dài.

+0

Vì, đằng sau hậu trường, yêu cầu khởi động các chuỗi riêng biệt để thực hiện các công việc lâu dài hơn và tôi sẽ không thể dễ dàng nói chuyện lại với các chủ đề đó nếu tôi đóng kết nối đầu tiên. Những gì tôi có bây giờ là các chủ đề bằng văn bản cho cơ sở dữ liệu và các cuộc gọi ajax kéo bất kỳ một trong các máy chủ web trong trang trại mỗi vài giây, mà đọc cơ sở dữ liệu và xem nếu bất cứ điều gì đã hoàn thành. Bằng cách sử dụng một ổ cắm web cho biết mở, tôi khóa nó xuống một máy chủ (trong một chút thời gian), và cung cấp cho các chủ đề khả năng phản hồi trực tiếp, mà không có cơ sở dữ liệu liên quan. –

Các vấn đề liên quan