建设简单网站的图纸,wordpress添加,网站服务器关闭,关于美丽乡村建设的活动和网站关于websocket的请求必须登录#xff0c;实现websocket需要登录后才可使用#xff0c;不登录不能建立连接。
后台spring security配置添加websocket的请求可以匿名访问#xff0c;关于websocket的请求不要认证就可以随意访问#xff0c;去除匿名访问后#xff0c;前端在与…关于websocket的请求必须登录实现websocket需要登录后才可使用不登录不能建立连接。
后台spring security配置添加websocket的请求可以匿名访问关于websocket的请求不要认证就可以随意访问去除匿名访问后前端在与websocket建立链接无法在请求头里直接加入Authorization token信息任何关于websocket的请求都无法通过token认证。
解决办法 使用websocket的Sec-WebSocket-Protocol参数将token传回后台后台借助HttpServletRequestWrapper重新生成新的请求信息实现使用一套登录认证拦截
原理 HttpServletRequestWrapper 采用装饰者模式对HttpServletRequest进行包装我们可以通过继承HttpServletRequestWrapper 类去重写getParameterValuesgetParameter等方法实际还是调用 HttpServletRequest的相对应方法但是可以对方法的结果进行改装。
1、前端webSock.js
与webSocke建立连接
var websock null;var global_callback null;
var serverPort 8080; // webSocket连接端口
var wsurl ws:// window.location.hostname : serverPort/websocket/message;/*** 创建socket连接* param callback*/
function createWebSocket(callback) {if (websock null || typeof websock ! WebSocket) {initWebSocket(callback);}
}/*** 初始化socket* param callback*/
function initWebSocket(callback) {global_callback callback;// 初始化websocket//token会放在请求的Sec-WebSocket-Protocol参数里面websock new WebSocket(wsurl,[你的token]);websock.onmessage function (e) {websocketOnMessage(e);};websock.onclose function (e) {websocketClose(e);};websock.onopen function () {websocketOpen();};// 连接发生错误的回调方法websock.onerror function () {console.log(WebSocket连接发生错误);};
}/*** 实际调用的方法*/
function sendSock(agentData ) {if (websock.readyState websock.OPEN) {// 若是ws开启状态websocketsend(agentData);} else if (websock.readyState websock.CONNECTING) {// 若是 正在开启状态则等待1s后重新调用setTimeout(function () {sendSock(agentData);}, 1000);} else {// 若未开启 则等待1s后重新调用setTimeout(function () {sendSock(agentData);}, 1000);}
}/*** 关闭*/
function closeSock() {websock.close();
}/*** 数据接收*/
function websocketOnMessage(msg) {// 收到信息为Blob类型时let result null;// debuggerif (msg.data instanceof Blob) {const reader new FileReader();reader.readAsText(msg.data, UTF-8);reader.onload (e) {result reader.result;// console.log(websocket收到, result);global_callback(result);};} else {result msg.data;// console.log(websocket收到, result);global_callback(result);}
}/*** 数据发送*/
function websocketsend(agentData) {// console.log(发送数据 agentData);websock.send(agentData);
}/*** 异常关闭*/
function websocketClose(e) {// console.log(connection closed ( e.code ));
}function websocketOpen(e) {// console.log(连接打开);
}export { sendSock, createWebSocket, closeSock };2、后端的JWT拦截 前提 spring security配置类不允许/websocket匿名访问需要鉴权才可以使用
2.1 先实现 HeaderMapRequestWrapper继承HttpServletRequestWrapper 来实现修改HttpServletRequest的请求参数
/*** 修改header信息key-value键值对儿加入到header中*/
public class HeaderMapRequestWrapper extends HttpServletRequestWrapper {private static final Logger LOGGER LoggerFactory.getLogger(HeaderMapRequestWrapper.class);/*** construct a wrapper for this request** param request*/public HeaderMapRequestWrapper(HttpServletRequest request) {super(request);}private MapString, String headerMap new HashMap();/*** add a header with given name and value** param name* param value*/public void addHeader(String name, String value) {headerMap.put(name, value);}Overridepublic String getHeader(String name) {String headerValue super.getHeader(name);if (headerMap.containsKey(name)) {headerValue headerMap.get(name);}return headerValue;}/*** get the Header names*/Overridepublic EnumerationString getHeaderNames() {ListString names Collections.list(super.getHeaderNames());for (String name : headerMap.keySet()) {names.add(name);}return Collections.enumeration(names);}Overridepublic EnumerationString getHeaders(String name) {ListString values Collections.list(super.getHeaders(name));if (headerMap.containsKey(name)) {values Arrays.asList(headerMap.get(name));}return Collections.enumeration(values);}
}token过滤器 JWT认证拦截器修改
Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException{/*** 通过request的url判断是否为websocket请求* 如果为websocket请求先处理Authorization*/if(request.getRequestURI().contains(/websocket)){HeaderMapRequestWrapper requestWrapper new HeaderMapRequestWrapper((HttpServletRequest) request);//修改header信息 将websocket请求中的Sec-WebSocket-Protocol值取出处理后放入认证参数key//此处需要根据自己的认证方式进行修改 Authorization 和 BearerrequestWrapper.addHeader(Authorization,Bearer request.getHeader(Sec-WebSocket-Protocol));request (HttpServletRequest) requestWrapper;}//处理完后就可以走系统正常的登录认证权限认证逻辑了//下边就是自己的验证token 登陆逻辑LoginUser loginUser getLoginUser(request);·······chain.doFilter(request, response);}websocket如何携带header或参数
var ws new WebSocket(ws://url?userid1);
ebsocket如何携带header
最近项目组接到新需求需要websocket连接时在header里面传递token由于token较长不适合在url中直接拼接。
网上查阅了相关的资料websocket没有像http那样可以只定义请求头的一些参数只有一个Sec-WebSocket-Protocol属性用于自定义子协议。
意思就是说可以将token当做一个参数传递给后端只不过参数的封装形式是以Sec-WebSocket-Protocol为key的一个header属性值。
后台接收到websocket连接后可以通过下述代码获取到token值。
request.getHeader(Sec-WebSocket-Protocol)
需要注意的是如果前端通过websocket连接时指定了Sec-WebSocket-Protocol后端接收到连接后必须原封不动的将Sec-WebSocket-Protocol头信息返回给前端否则连接会抛出异常。
前端代码格式 let WebSocket new WebSocket(url[protocols]);
url 要连接的URLWebSocket服务器响应的URL。 protocols 可选 一个协议字符串或者一个包含协议字符串的数组。这些字符串用于指定子协议这样单个服务器可以实现多个WebSocket子协议例如您可能希望一台服务器能够根据指定的协议protocol处理不同类型的交互。如果不指定协议字符串则假定为空字符串。
const webSocket new WebSocket(url[token]);
后端依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-websocket/artifactId
/dependency
java代码
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Objects;/*** webSocket握手拦截器* since 2023年12月16日16:57:52*/
Component
public class PortalHandshakeInterceptor implements HandshakeInterceptor {private final Logger logger LoggerFactory.getLogger(PortalHandshakeInterceptor.class);Resourceprivate UserClient userClient;/*** 初次握手访问前* param request* param serverHttpResponse* param webSocketHandler* param map* return*/Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, MapString, Object map) {logger.info(HandshakeInterceptor beforeHandshake start...);if (request instanceof ServletServerHttpRequest) {HttpServletRequest req ((ServletServerHttpRequest) request).getServletRequest();String authorization req.getHeader(Sec-WebSocket-Protocol);logger.info(authorization {}, authorization);if (Objects.isNull(userClient)){userClient (UserClient) SpringContextUtil.getBean(userClient);}TokenVO tokenVO userClient.checkToken(authorization, authorization);Long userId tokenVO.getUserId();logger.info(userId {}, tokenVO {}, userId, tokenVO);if (Objects.isNull(userId)){serverHttpResponse.setStatusCode(HttpStatus.FORBIDDEN);logger.info(【beforeHandshake】 authorization Parse failure. authorization {}, authorization);return false;}//存入数据方便在hander中获取这里只是在方便在webSocket中存储了数据并不是在正常的httpSession中存储想要在平时使用的session中获得这里的数据需要使用session 来存储一下map.put(MagicCode.WEBSOCKET_USER_ID, userId);map.put(MagicCode.WEBSOCKET_CREATED, System.currentTimeMillis());map.put(MagicCode.TOKEN, authorization);map.put(HttpSessionHandshakeInterceptor.HTTP_SESSION_ID_ATTR_NAME, req.getSession().getId());logger.info(【beforeHandshake】 WEBSOCKET_INFO_MAP: {}, map);}logger.info(HandshakeInterceptor beforeHandshake end...);return true;}/*** 初次握手访问后将前端自定义协议头Sec-WebSocket-Protocol原封不动返回回去否则会报错* param request* param serverHttpResponse* param webSocketHandler* param e*/Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {logger.info(HandshakeInterceptor afterHandshake start...);HttpServletRequest httpRequest ((ServletServerHttpRequest) request).getServletRequest();HttpServletResponse httpResponse ((ServletServerHttpResponse) serverHttpResponse).getServletResponse();if (StringUtils.isNotEmpty(httpRequest.getHeader(Sec-WebSocket-Protocol))) {httpResponse.addHeader(Sec-WebSocket-Protocol, httpRequest.getHeader(Sec-WebSocket-Protocol));}logger.info(HandshakeInterceptor afterHandshake end...);}
}