今天在springboot 中调试websocket,然后发现被shiro拦截了,具体解决办法如下:
在shiro 拦截器中配置websoket不需认证:
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
//oauth过滤
Map<String, Filter> filters = new HashMap<>();
filters.put("oauth2", new OAuth2Filter());
shiroFilter.setFilters(filters);
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/sys/login", "anon");
filterMap.put("/swagger/**", "anon");
filterMap.put("/index/**", "anon");
filterMap.put("/libs/**", "anon");
filterMap.put("/home/**", "anon");
filterMap.put("/v2/api-docs", "anon");
filterMap.put("/swagger-ui.html", "anon");
filterMap.put("/swagger-resources/**", "anon");
filterMap.put("/captcha.jpg", "anon");
filterMap.put("/aaa.txt", "anon");
filterMap.put("/webSocket/**", "anon"); //配置websocket不需认证
filterMap.put("/**", "oauth2");
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}
websocket服务器端代码如下:
pom.xml中引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
开启注解
/**
* websocket 配置类
*/
@Configuration
public class WebSocketConfig {
/**
* ServerEndpointExporter 作用
*
* 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint
*
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
新建websocket服务类
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* websocket 服务类
*/
@ServerEndpoint("/webSocket/{token}")
@Component
@Slf4j
public class WebSocketServer {
//静态变量,用来记录当前在线连接数
private static AtomicInteger onlineNum = new AtomicInteger();
//concurrent包的线程安全set,用来存放每个客户端对应的webSocketServer对象;
private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<String, Session>();
//发送消息
public void sendMessage(Session session, String message) throws IOException {
if (session != null) {
synchronized (session) {
session.getBasicRemote().sendText(message);
}
}
}
//给指定的用户发送消息,token为用户登录后的令牌
public void sendInfo(String token, String message) {
Session session = sessionPools.get(token);
try {
sendMessage(session, message);
} catch (Exception e) {
log.error("webSocket发送消息失败:"+token, e);
}
}
//建立连接成功调用
@OnOpen
public void onOpen(Session session, @PathParam(value="token") String token) {
sessionPools.put(token, session);
addOnlineCount();
}
//关闭连接时调用
@OnClose
public void onClose(@PathParam(value="token") String token) {
if (StringUtils.isNotEmpty(token)) {
sessionPools.remove(token);
subOnlineCount();
}
}
//收到客户端消息
@OnMessage
public void onMessage(String message) {
for (Session session : sessionPools.values()) {
try {
sendMessage(session, message);
} catch (Exception e) {
log.error("webSocket 发送消息失败:", e);
continue;
}
}
}
@OnError
public void onError(Throwable error) {
log.error("websocket出错", error.getMessage());
}
public static void addOnlineCount() {
onlineNum.incrementAndGet();
}
public static void subOnlineCount() {
onlineNum.decrementAndGet();
}
}
服务器调用直接注入服务
@Autowired
private WebSocketServer webSocketServer;
WebSocketInfo info = WebSocketInfo.builder().message("你有一条消息需要处理!").build();
webSocketServer.sendInfo(token, JsonMapper.toJsonString(info));
前端代码:
mounted() {
this.initWebSocket()
},
methods: {
initWebSocket () {
let host = document.location.host;
let token = this.$cookie.get("token")
let socketUrl = "ws://localhost:8090/jg/webSocket/" + token
this.websock = new WebSocket(socketUrl);//这个连接ws://固定,后面的根据自己的IP和端口进行改变,我设置监听是8090
this.websock.onmessage = this.webSocketOnMessage
this.websock.onerror = this.webSocketOnError
this.websock.onopen = this.webSocketOnOpen
this.websock.onclose = this.webSocketClose
},
webSocketOnOpen () { //打开
this.websock.send("发送数据");
},
webSocketOnError () { //连接错误
console.log( 'WebSocket连接失败')
},
webSocketOnMessage (e) { // 数据接收
let obj = JSON.parse(e.data)
this.$message({
type: 'info',
message: obj.message,
duration: 1000,
})
},
webSocketClose (e) { // 关闭连接
console.log('已关闭连接', e)
}
},
destroyed () {
if (this.websock != null) {
this.websock.close() // 页面销毁后断开websocket连接
}
}
其中websocket路径配置:ws://localhost:8090/jg/webSocket/ 加了前缀是因为springboot配置了前缀:
server:
tomcat:
uri-encoding: UTF-8
max-threads: 1000
min-spare-threads: 30
port: 8090
connection-timeout: 5000ms
servlet:
context-path: /jg
《思考中医》