当前位置: 首页 > 知识库问答 >
问题:

在没有spring身份验证的情况下通过web套接字多次应答

莫逸仙
2023-03-14

注意:关于我最终得出的结论,请参阅问题底部的更新。

我需要通过发送请求消息的web套接字对请求发送多个响应,第一个响应快速发送,其他响应在数据验证后发送(大约10到60秒后,来自多个并行线程)。

我很难获得稍后的响应来停止在所有打开的web套接字上广播。如何让它们只发送到初始web套接字?或者我应该使用Spring STOMP之外的东西(因为,老实说,我只想将消息路由到各种功能,我不需要或不想广播到其他web套接字,所以我怀疑我可以自己编写消息分发器,即使它正在重新发明轮子)。

我没有使用Spring身份验证(这正在被改造为遗留代码)。

在最初的返回消息中,我可以使用@SendToUser,即使我们没有用户,Spring也只将返回值发送给发送消息的websocket。(见此问题)。

不过,对于较慢的响应,我认为我需要使用SimpMessageTemplate。convertAndSendToUser(用户、目的地、消息),但我不能,因为我必须传入用户,而且我无法确定@SendToUser使用的是什么用户。我试图按照这个问题中的步骤进行操作,但在未经过身份验证的情况下无法正常工作(在本例中,principal.getName()返回null)。

我已经为原型大大简化了这一点,所以不要担心同步线程或任何事情。我只希望Web套接字正常工作。

这是我的控制器:

@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)
        {
        }
    }
  }
}

为了记录在案,这里是浏览器端:

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();
    });
});

下面是配置:

@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();
    }
}

更新:由于信息可能通过原始套接字以外的其他网络套接字发送所涉及的安全问题,我最终向我的团队建议我们不要使用STOMP over Web Sockets的Spring 4.0实现。我理解为什么Spring团队这样做,它比我们需要的更强大,但是我们项目的安全限制足够严格,实际要求也足够简单,所以我们决定走一条不同的路。这不会使下面的答案无效,所以请根据您的项目需求做出您自己的决定。至少我们都有希望了解该技术的局限性,无论好坏。

共有2个答案

张勇
2023-03-14

这不是完整的答案。只是一般的考虑和建议。你不能通过同一个套接字做不同的事情或连接类型。为什么不为不同的工作使用不同的套接字呢?有些有身份验证,有些没有。有些用于快速任务,有些用于长时间执行。

瞿博易
2023-03-14

你为什么不为每个客户使用一个单独的主题?

>

var sessionId=数学。随机()。toString(36)。子串(7)

客户端订阅/topic/testwsresponse/{sessionId},然后向“/app/testws/{sessionId}”发送消息。

本质上,当您使用用户目的地时,Spring在内部也做了类似的事情。由于您不使用Spring身份验证,因此您不能依赖此机制,但您可以轻松实现自己的身份验证,正如我上面所述。

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);
    });
}); 

控制器:

@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)
            {
            }
        }
    }
}

刚刚测试过,工作正常。

 类似资料:
  • “laravel/框架”:“5.7.*” “tymon/jwt认证”:“开发人员开发” 我正在尝试创建一个添加了自定义声明的JWT令牌,而不使用auth(这意味着我不希望从凭据创建令牌)。这是为了创建不需要登录的令牌,例如忘记/重置密码等。 使用Tymon/JWTAuth(https://github.com/tymondesigns/jwt-auth)由于最新的Laravel存在问题,因此建议加

  • 问题内容: 问题: 我们有一个基于Spring MVC的RESTful API,其中包含敏感信息。该API应该是安全的,但是不希望随每个请求一起发送用户凭证(用户/密码组合)。根据REST准则(和内部业务要求),服务器必须保持无状态。该API将由另一台服务器以mashup方式使用。 要求: 客户端使用凭据向(不受保护的URL)发出请求;服务器返回一个安全令牌,该令牌包含足够的信息供服务器验证未来的

  • 我正在运行带有公开WebSocketendpoint的服务器。下面是我的: 问题是如何使用或或查询参数实现建立WS连接的身份验证? 更好的选择是避免使用Spring Security。 多谢了。

  • 我有一个大的3D游戏,让玩家建立和创造有趣和巨大的世界,并保存到磁盘上的windows Phone7。 这款游戏使用了XNA,并且做了很多silverlight或SLXNA混合应用不支持的事情。 我想让玩家在那里备份,保存文件到他们的skydrive(最好)或dropbox,但经过一个多星期的努力,我得到了一些工作的暗示,我什么也没有... 似乎eather的每个示例都内置(并且需要)siverl

  • 我试图通过Postman访问我的简单API调用。它不工作,但它是在浏览器工作。 警告:不建议在没有服务器身份验证的情况下建立SSL连接。根据MySQL 5.5.45+、5.6.26+和5.7.6+的要求,如果未设置显式选项,默认情况下必须建立SSL连接。为了符合不使用SSL的现有应用程序,verifyServerCertificate属性设置为'false'。您需要通过设置usessl=false

  • > 如何在没有用户身份验证的情况下从Instagram获取用户的媒体? 现在是否还有不使用访问令牌获取instagram提要的方法(06/2016)? 我可以通过抓取用户的网页来检索前二十个项目,但这不是一个好的或标准的方法,尤其是当Instagram不正式支持它的时候。