当前位置:网站首页>Using SA token to solve websocket handshake authentication
Using SA token to solve websocket handshake authentication
2022-07-04 10:36:00 【Kongming Kongming】
Preface
Compared with Http Single communication mode ,WebSocket You can actively push messages from the server to the browser , This feature can help us accomplish things like Order message push 、IM Live chat And other specific businesses .
However WebSocket I am right “ Identity Authentication ” No direct support , The default connection to the client is “ All's fish that comes to his net ”, So authentication and authorization , We have to do it ourselves .
Sa-Token It's a java Authorization framework , It mainly solves login authentication 、 Permission authentication 、 Single sign on 、OAuth2、 Micro service gateway Authentication And so on .
Now let's introduce how to WebSocket In the integration Sa-Token Identity Authentication , Ensure the security of the connection .
Two ways to integrate
We will introduce the two most common integrations in turn WebSocket The way :
- Java Original version :javax.websocket.Session
- Spring Package version :WebSocketSession
I don't say much nonsense , Directly :
Mode one :Java Original version javax.websocket.Session
1、 The first is introduction pom.xml rely on
<!-- SpringBoot rely on --><dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid></dependency><!-- WebScoket rely on --><dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-websocket</artifactid> </dependency><!-- Sa-Token Permission authentication , Online document :http://sa-token.dev33.cn/ --><dependency> <groupid>cn.dev33</groupid> <artifactid>sa-token-spring-boot-starter</artifactid> <version>1.29.0</version></dependency>
2、 Login interface , Used to get a session token
/** * Log on to the test */@[email protected]("/acc/")public class LoginController { // Test login ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456 @RequestMapping("doLogin") public SaResult doLogin(String name, String pwd) { // Here is only a simulation example , Real projects need to query data from the database for comparison if("zhang".equals(name) && "123456".equals(pwd)) { StpUtil.login(10001); return SaResult.ok(" Login successful ").set("token", StpUtil.getTokenValue()); } return SaResult.error(" Login failed "); } // ... }
3、WebSocket Connection processing
@[email protected]("/ws-connect/{satoken}")public class WebSocketConnect { /** * Fixed prefix */ private static final String USER_ID = "user_id_"; /** * Deposit Session aggregate , Easy to push messages (javax.websocket.Session) */ private static ConcurrentHashMap<string, session> sessionMap = new ConcurrentHashMap<>(); // monitor : Successful connection @OnOpen public void onOpen(Session session, @PathParam("satoken") String satoken) throws IOException { // according to token Get the corresponding userId Object loginId = StpUtil.getLoginIdByToken(satoken); if(loginId == null) { session.close(); throw new SaTokenException(" The connection fails , Invalid Token:" + satoken); } // put To the assembly , Convenient follow-up operation long userId = SaFoxUtil.getValueByType(loginId, long.class); sessionMap.put(USER_ID + userId, session); // Give me a hint. String tips = "Web-Socket Successful connection ,sid=" + session.getId() + ",userId=" + userId; System.out.println(tips); sendMessage(session, tips); } // monitor : Connection is closed @OnClose public void onClose(Session session) { System.out.println(" Connection is closed ,sid=" + session.getId()); for (String key : sessionMap.keySet()) { if(sessionMap.get(key).getId().equals(session.getId())) { sessionMap.remove(key); } } } // monitor : Received a message from the client @OnMessage public void onMessage(Session session, String message) { System.out.println("sid by :" + session.getId() + ", From :" + message); } // monitor : Something goes wrong @OnError public void onError(Session session, Throwable error) { System.out.println("sid by :" + session.getId() + ", An error occurred "); error.printStackTrace(); } // --------- // Push a message to the specified client public static void sendMessage(Session session, String message) { try { System.out.println(" towards sid by :" + session.getId() + ", send out :" + message); session.getBasicRemote().sendText(message); } catch (IOException e) { throw new RuntimeException(e); } } // Push a message to a specified user public static void sendMessage(long userId, String message) { Session session = sessionMap.get(USER_ID + userId); if(session != null) { sendMessage(session, message); } } }
4、WebSocket To configure
/** * Turn on WebSocket Support */@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
5、 Start class
@SpringBootApplicationpublic class SaTokenWebSocketApplication { public static void main(String[] args) { SpringApplication.run(SaTokenWebSocketApplication.class, args); } }
Set up , Start project
6、 test
1、 First, we access the login interface , Get the conversation token
http://localhost:8081/acc/doLogin?name=zhang&pwd=123456
As shown in the figure :
2、 Then we'll find one WebSocket Connect to the online test page , for example :https://www.bejson.com/httputil/websocket/
Connection address :
ws://localhost:8081/ws-connect/302ee2f8-60aa-42aa-8ecb-eeae5ba57015
As shown in the figure :
3、 If we enter a wrong token, What will happen? ?
You can see , The connection will be immediately disconnected !
Mode two :Spring Package version :WebSocketSession
1、 ditto : The first is introduction pom.xml rely on
<!-- SpringBoot rely on --><dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid></dependency><!-- WebScoket rely on --><dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-websocket</artifactid> </dependency><!-- Sa-Token Permission authentication , Online document :http://sa-token.dev33.cn/ --><dependency> <groupid>cn.dev33</groupid> <artifactid>sa-token-spring-boot-starter</artifactid> <version>1.29.0</version></dependency>
2、 Login interface , Used to get a session token
/** * Log on to the test */@[email protected]("/acc/")public class LoginController { // Test login ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456 @RequestMapping("doLogin") public SaResult doLogin(String name, String pwd) { // Here is only a simulation example , Real projects need to query data from the database for comparison if("zhang".equals(name) && "123456".equals(pwd)) { StpUtil.login(10001); return SaResult.ok(" Login successful ").set("token", StpUtil.getTokenValue()); } return SaResult.error(" Login failed "); } // ... }
3、WebSocket Connection processing
/** * Handle WebSocket Connect */public class MyWebSocketHandler extends TextWebSocketHandler { /** * Fixed prefix */ private static final String USER_ID = "user_id_"; /** * Deposit Session aggregate , Easy to push messages */ private static ConcurrentHashMap<string, websocketsession> webSocketSessionMaps = new ConcurrentHashMap<>(); // monitor : Connection on @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { // put To the assembly , Convenient follow-up operation String userId = session.getAttributes().get("userId").toString(); webSocketSessionMaps.put(USER_ID + userId, session); // Give me a hint. String tips = "Web-Socket Successful connection ,sid=" + session.getId() + ",userId=" + userId; System.out.println(tips); sendMessage(session, tips); } // monitor : Connection is closed @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { // Remove from collection String userId = session.getAttributes().get("userId").toString(); webSocketSessionMaps.remove(USER_ID + userId); // Give me a hint. String tips = "Web-Socket Connection is closed ,sid=" + session.getId() + ",userId=" + userId; System.out.println(tips); } // Received a message @Override public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException { System.out.println("sid by :" + session.getId() + ", From :" + message); } // ----------- // Push a message to the specified client public static void sendMessage(WebSocketSession session, String message) { try { System.out.println(" towards sid by :" + session.getId() + ", send out :" + message); session.sendMessage(new TextMessage(message)); } catch (IOException e) { throw new RuntimeException(e); } } // Push a message to a specified user public static void sendMessage(long userId, String message) { WebSocketSession session = webSocketSessionMaps.get(USER_ID + userId); if(session != null) { sendMessage(session, message); } } }
4、WebSocket Front interceptor
/** * WebSocket The front interceptor of handshake */public class WebSocketInterceptor implements HandshakeInterceptor { // Trigger before handshake (return true Will shake hands successfully ) @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler, Map<string, object> attr) { System.out.println("---- Trigger before handshake " + StpUtil.getTokenValue()); // Refuse to shake hands without logging in if(StpUtil.isLogin() == false) { System.out.println("---- Unauthorized client , The connection fails "); return false; } // Mark userId, Shake hands with success attr.put("userId", StpUtil.getLoginIdAsLong()); return true; } // Trigger after handshake @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { System.out.println("---- Trigger after handshake "); } }
5、WebSocket To configure
/** * WebSocket Related configuration */@[email protected] class WebSocketConfig implements WebSocketConfigurer { // register WebSocket processor @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) { webSocketHandlerRegistry // WebSocket Connecting the processor .addHandler(new MyWebSocketHandler(), "/ws-connect") // WebSocket Interceptor .addInterceptors(new WebSocketInterceptor()) // Allow cross-domain .setAllowedOrigins("*"); }}
6、 Start class
/** * Sa-Token Integrate WebSocket Authentication example */@SpringBootApplicationpublic class SaTokenWebSocketSpringApplication { public static void main(String[] args) { SpringApplication.run(SaTokenWebSocketSpringApplication.class, args); } }
Start project , Start testing
7、 test
1、 First access the login interface , Get the conversation token
http://localhost:8081/acc/doLogin?name=zhang&pwd=123456
As shown in the figure :
2、 Then open the WebSocket Connect to the online test page , for example :https://www.bejson.com/httputil/websocket/
Connection address :
ws://localhost:8081/ws-connect?satoken=fe6e7dbd-38b8-4de2-ae05-cda7e36bf2f7
As shown in the figure :
notes : Here the url Pass on Token Because it is more convenient on the third-party test page , In real projects, you can learn from Cookie、Header Parameters 、url Parameters Choose one of three ways to pass the session token , Same effect
3、 If you enter an incorrect Token
The connection fails !
The sample address
The above code has been uploaded git, The sample address : Code cloud :sa-token-demo-websocket
Reference material
- Gitee Address :https://gitee.com/dromara/sa-token
- GitHub Address :https://github.com/dromara/sa-token
- Sa-Token Official website :https://sa-token.dev33.cn/
</string,></string,></string,>
边栏推荐
- [Galaxy Kirin V10] [server] iSCSI deployment
- Rhcsa day 9
- 【Day2】 convolutional-neural-networks
- Learning XML DOM -- a typical model for parsing XML documents
- Introduction to tree and binary tree
- Sword finger offer 05 (implemented in C language)
- Es advanced series - 1 JVM memory allocation
- AUTOSAR from getting started to mastering 100 lectures (106) - SOA in domain controllers
- Differences among opencv versions
- uniapp---初步使用websocket(长链接实现)
猜你喜欢
leetcode1-3
If the uniapp is less than 1000, it will be displayed according to the original number. If the number exceeds 1000, it will be converted into 10w+ 1.3k+ display
PHP code audit 3 - system reload vulnerability
[Galaxy Kirin V10] [desktop] build NFS to realize disk sharing
The future education examination system cannot answer questions, and there is no response after clicking on the options, and the answers will not be recorded
Rhcsa - day 13
Introduction to tree and binary tree
Debug:==42==ERROR: AddressSanitizer: heap-buffer-overflow on address
[Galaxy Kirin V10] [desktop] printer
MongoDB数据日期显示相差8小时 原因和解决方案
随机推荐
From programmers to large-scale distributed architects, where are you (2)
RHCE - day one
If you don't know these four caching modes, dare you say you understand caching?
How do microservices aggregate API documents? This wave of show~
【Day2】 convolutional-neural-networks
leetcode842. Split the array into Fibonacci sequences
IPv6 comprehensive experiment
【FAQ】华为帐号服务报错 907135701的常见原因总结和解决方法
Realsense of d435i, d435, d415, t265_ Matching and installation of viewer environment
Occasional pit compiled by idea
Sword finger offer 05 (implemented in C language)
六月份阶段性大总结之Doris/Clickhouse/Hudi一网打尽
BGP ---- border gateway routing protocol ----- basic experiment
Student achievement management system (C language)
OSPF comprehensive experiment
How to quickly parse XML documents through C (in fact, other languages also have corresponding interfaces or libraries to call)
Press the button wizard to learn how to fight monsters - identify the map, run the map, enter the gang and identify NPC
Two way process republication + routing policy
From programmers to large-scale distributed architects, where are you (I)
Does any teacher know how to inherit richsourcefunction custom reading Mysql to do increment?