spring框架下基于websocket握手的拦截器配置(HandshakeInterceptor)

本次博客为记录小程序开发过程中遇到的问题,总结一些经验!

对于拦截器的配置,相信很多人都会碰到坑,当然遇到的坑越多,你的技能提升的越快,我觉得是对的。做项目是可以提升一个程序员的技能,考验开发能力的最好方法之一。

下面直接进入正题:

本次拦截器的配置主要是要实现在websocket握手前,对用户信息的验证及筛选。

在本系统中原先已实现了登录验证的拦截器,即判断小程序请求头中是否存在登录态信息。是则通过,不是则拦截。

同样的,如果想要在websocket握手前也达到此目的,在原先的mvc拦截器下加入是不行的,针对websocket官方有参考的接口HandshakeInterceptor,所以应该另外配置此拦截器。网上也有很多教程可以看,可以参考Java整合WebSocket实现实时推送(注解版)写的非常不错。

当然,该博客只是介绍了基本的配置,想要完成具体的配置还需完善。

 

A、

因为要区分login拦截器,我们首先应该对url进行过滤,不同的url应该去往不同的拦截器,首先在web.xml中添加<url-pattern></url-pattern>

 <!-- 前端控制器 -->
  <servlet>
  	<servlet-name>springmvc</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  	<init-param>
  		<param-name>contextConfigLocation</param-name>
  		<param-value>classpath:springmvc-config.xml</param-value>
  	</init-param>
  	<load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
  	<servlet-name>springmvc</servlet-name>
  	<url-pattern>*.a</url-pattern>
  	<url-pattern>*.c</url-pattern>
  </servlet-mapping>

其中有两个<url-pattern></url-pattern>对不同的url进行过滤,程序中仅允许.a或.c结尾的url通过。

 

B、

接下来来到springmvc的配置文件下:

<!-- websocket握手 -->
	<bean id="wxsocket" class="com.yq.handler.MessageHandler"/>
	
	<websocket:handlers allowed-origins="*">
		<websocket:mapping path="/socketConnect.c" handler="wxsocket"/>
		<websocket:handshake-interceptors>
			<bean class="com.yq.interceptor.WebSocketInterceptor"/>
			
		</websocket:handshake-interceptors>
	</websocket:handlers>

添加以上配置。注解方面不是很了解,不知道行不行。

完成到这一步,在前端的wx.connectSocket下已经能够成功响应了并接入拦截器内部。

注意:

在开发中,发现很多人会遇到wss://...报错的问题,其实很简单

只需改成ws就可以了,因为wss表示的是加了SSL安全协议的请求,而开发过程中一般使用的都是本地ip。

 

C、

再来看HandshakeInterceptor具体配置

package com.yq.interceptor;

import java.util.Collection;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;

import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

import com.yq.utils.RedisUtil;


/*
 * websocket连接拦截器
 */

public class WebSocketInterceptor extends HttpSessionHandshakeInterceptor{
	
	@Autowired
	RedisUtil redisUtil;
	
	/*
	 * 握手后
	 * @see org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor#afterHandshake(org.springframework.http.server.ServerHttpRequest, org.springframework.http.server.ServerHttpResponse, org.springframework.web.socket.WebSocketHandler, java.lang.Exception)
	 */
	@Override
	public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Exception ex) {
		
		System.out.println("对方正在输入...");
	}

	/*
	 * 握手前
	 * @see org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor#beforeHandshake(org.springframework.http.server.ServerHttpRequest, org.springframework.http.server.ServerHttpResponse, org.springframework.web.socket.WebSocketHandler, java.util.Map)
	 */
	@Override
	public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Map<String, Object> attributes) throws Exception {
		HttpHeaders headers = request.getHeaders();
		String sessionid = headers.getFirst("sessionid");
		System.out.println("拦截器获取的sessionid"+sessionid);
		if(sessionid!=null && sessionid != "") {
			
			//检查是否存在
			if(redisUtil.isExist(sessionid)) {
				System.out.println("通过不拦截");
				response.setStatusCode(HttpStatus.OK);
				return true;
			}
			//session过期拦截
			System.out.println("拦截请求1:sessionid已过期!");
			response.setStatusCode(HttpStatus.FORBIDDEN);
			return false;
			
		}
		System.out.println("拦截请求2:sessionid为空");
		response.setStatusCode(HttpStatus.FORBIDDEN);
		
		return false;
	}

	@Override
	public Collection<String> getAttributeNames() {
		// TODO Auto-generated method stub
		return super.getAttributeNames();
	}

	@Override
	public boolean isCopyAllAttributes() {
		// TODO Auto-generated method stub
		return super.isCopyAllAttributes();
	}

	@Override
	public boolean isCopyHttpSessionId() {
		// TODO Auto-generated method stub
		return super.isCopyHttpSessionId();
	}

	@Override
	public boolean isCreateSession() {
		// TODO Auto-generated method stub
		return super.isCreateSession();
	}

	@Override
	public void setCopyAllAttributes(boolean copyAllAttributes) {
		// TODO Auto-generated method stub
		super.setCopyAllAttributes(copyAllAttributes);
	}

	@Override
	public void setCopyHttpSessionId(boolean copyHttpSessionId) {
		// TODO Auto-generated method stub
		super.setCopyHttpSessionId(copyHttpSessionId);
	}

	@Override
	public void setCreateSession(boolean createSession) {
		// TODO Auto-generated method stub
		super.setCreateSession(createSession);
	}
	
}

D、

最后来看下实际效果

 

1、第一次登录:

前端显示连接失败,是因为第一次登录不存在登录态,设置登录态30s时间。此时需要提醒用户运行登录

后台运行结果也显示了相关信息

拦截器获取的sessionid
拦截请求2:sessionid为空

2、模拟长时间未登录,登录态过期(30s):

同样的过期的用户不可以连接,需要重新登陆,此时需要提醒用户重新登录

后台运行结果,过期

拦截器获取的sessionid6574123103e869e00d24b4071f1fb6ce
拦截请求1:sessionid已过期!

3、处于登录状态

可以看到成功连接并发送信息了

后台运行结果

拦截器获取的sessionid894ca3ec8fe8507b516e659a9e4a464f
通过不拦截
对方正在输入...
。。。websocket已连接
message:有消息请接收..发送中
。。。websocket已断开连接

 

其中HttpSessionHandshakeInterceptor为官方给出的HandshakeInterceptor接口的实现类。

那么这里主要是对beforeHandshake()握手前进行拦截处理的介绍

如果大家想要了解更多的信息可以去参考该接口的源码,简单易懂。

因为我是将登录态存于header当中,所以通过getheaders的方法获取头部信息

以上就是我HandshakeInterceptor配置的全部内容,拦截逻辑上可能不是很严谨,希望大家看到的可以指点指点。

总结:其实一般情况下并不需要这么麻烦,想要实现以上逻辑,只需在前端页面逻辑上做手脚就可以实现的了,就比如聊天页面,在进入前就应该进行登录验证,而不是在连接的时候进行验证。当然个人认为以上实现应该适用于提交任务后的消息提醒实现,类似于第一次表单提交的触发,并且不需要页面逻辑就能实现。

 

 

发布了33 篇原创文章 · 获赞 25 · 访问量 6891
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览