1. WebSocket 基础概念
什么是 WebSocket?
- WebSocket 是一种网络通信协议,提供了在单个 TCP 连接上进行全双工通信的方式。"全双工"意味着客户端和服务器可以同时发送和接收信息,这与传统的 HTTP 请求不同,后者是一种半双工通信方式(即一次只能进行一个请求或响应)。
WebSocket 与 HTTP 的区别
- 连接持续性:HTTP 协议是基于请求-响应模式的,通常在请求被服务端响应后连接就会关闭。而 WebSocket 在握手后就建立了一个持久的连接,直到客户端或服务器决定关闭这个连接。
- 实时性:WebSocket 支持实时数据传输,这对于需要快速响应的应用(如在线游戏、实时聊天等)来说非常重要。
- 头信息大小:WebSocket 的头信息比 HTTP 小,这意味着在数据传输时,WebSocket 的开销更小。
建立连接的过程
-
客户端请求:WebSocket 连接是通过 HTTP 请求“升级”来初始化的。客户端发送一个特殊的 HTTP 请求,包含
Upgrade: websocket
和Connection: Upgrade
头信息。 -
服务器响应:如果服务器支持 WebSocket,则会以一个状态码
101 Switching Protocols
响应,表示服务器同意改变协议。 - 数据传输:一旦握手完成,数据就可以通过这个连接双向传输。
使用场景
- 实时聊天应用
- 在线游戏
- 实时数据更新(如股票报价)
- 协作应用(如实时文档编辑)
WebSocket URL
- WebSocket URL 以
ws://
(非加密) 或wss://
(加密) 开头,类似于 HTTP 的http://
和 HTTPS 的https://
。
2. 在 Spring Boot 中使用 WebSocket
步骤 1: 添加依赖项
首先,在你的 pom.xml
文件中添加 Spring Boot 对 WebSocket 的支持。这通常意味着添加 spring-boot-starter-websocket
依赖。
xmlCopy code<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- 其他依赖 -->
</dependencies>
步骤 2: 配置 WebSocket
在 Spring Boot 应用中创建一个配置类来启用和配置 WebSocket。
@Configuration
@EnableWebSocketMessageBroker // 启用 WebSocket 消息代理
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 注册一个 WebSocket 端点,客户端将使用它连接到 WebSocket 服务器。
registry.addEndpoint("/ws").withSockJS();
// SockJS 用于兼容不支持 WebSocket 的浏览器
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 定义消息代理,用于将消息从一个客户端路由到另一个客户端
registry.setApplicationDestinationPrefixes("/app");
// 客户端将使用此前缀发送消息
registry.enableSimpleBroker("/topic");
// 定义了一个简单的消息代理,客户端可以订阅的前缀
}
}
这里使用了 STOMP(Simple Text Oriented Messaging Protocol)作为 WebSocket 的子协议。STOMP 提供了一个可互操作的线路格式,允许 STOMP 客户端与任何支持 STOMP 的消息代理进行交互。
步骤 3: 创建 WebSocket 控制器
接下来,创建一个控制器来处理发送到 WebSocket 的消息。
@Controller
public class WebSocketController {
@MessageMapping("/hello") // 定义消息的地址
@SendTo("/topic/greetings") // 定义客户端订阅的地址
public String greeting(String message) throws Exception {
// 当服务器接收到 "/app/hello" 的消息时,它会调用此方法
return "Hello, " + message + "!";
}
}
这个控制器将接收发送到 /app/hello
的消息,并将响应发送到 /topic/greetings
。
步骤 4: 客户端连接
在客户端,你需要使用一个合适的库来建立 WebSocket 连接。如果你的客户端是一个网页,你可以使用 SockJS 和 STOMP 客户端库。
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Test</title>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client/dist/sockjs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/stomp-websocket/lib/stomp.min.js"></script>
</head>
<body>
<script type="text/javascript">
var socket = new SockJS('/ws'); // 连接到服务器上的 WebSocket 端点
var stompClient = Stomp.over(socket); // 使用 STOMP 子协议
stompClient.connect({}, function (frame) {
// 成功连接后的回调函数
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
// 订阅 '/topic/greetings' 以接收消息
alert(JSON.parse(greeting.body).content);
});
});
function sendMessage() {
stompClient.send("/app/hello", {}, JSON.stringify({'name': "yourName"}));
// 向 '/app/hello' 发送消息
}
</script>
<button onclick="sendMessage()">Send Message</button>
</body>
</html>
2.Spring Security安全框架
Spring Security 是一个专门用于 Java 应用程序的安全框架。它为基于 Spring 的应用程序提供了全面的安全解决方案。
security提供了一个默认的登录页面,在没有登录的情况下所有的请求都会被拦截到该页面,默认的登录名和密码是可以改的在yml配置文件中
spring:
security:
user:
name: boss
password: 123
使用顺序
- 创建数据库
- 使用Mybatis管理dao层
- 创建密码解析器——PasswordEncoder
public class MyPasswordEncode implements PasswordEncoder {
/*
* 密码加密方法
* */
@Override
public String encode(CharSequence rawPassword) {
System.out.println("自定义密码解析器,encode方法执行");
return rawPassword.toString();
}
/**
* 校验密码明文和密文是否相同的方法
* @param rawPassword 明文密码,客户端传递的
* @param encodedPassword 密文密码,服务器中存储的
* @return
*/
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
// 先使用encode方法,用相同的加密策略,加密明文,在对比密文
return encode(rawPassword).equals(encodedPassword);
}
/*
* 是否需要升级密码解析策略,强化密码解析策略
* */
@Override
public boolean upgradeEncoding(String encodedPassword) {
return PasswordEncoder.super.upgradeEncoding(encodedPassword);
}
}
创建配置类管理该解析器——解析器唯一
- 定义登录服务类型——方法的实现内容是:根据用户名查询用户对象,和用户权限列表。(MyUserDetailsServiceImpl)
/**
* 登录服务实现类型
*/
@Component
public class MyUserDetailsServiceImpl implements UserDetailsService {
@Autowired
userMapper userMapper;
/**
* 方法的实现内容是:根据用户名查询用户对象,和用户权限列表。
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 根据用户名查询用户
User user =userMapper.SelectByUserName(username);
// 判断用户是否存在
if (user==null)
{
throw new UsernameNotFoundException("用户名或者密码错误");
}
// 返回UserDetails接口类型对象
org.springframework.security.core.userdetails.User result=
new org.springframework.security.core.userdetails.User(
username,//登录用户的用户名
user.getPassword(),//登录用户的密码,是服务器保存的密文
AuthorityUtils.NO_AUTHORITIES//工具提供的无权限空集合,
);
return result;
}
}
sercurity**默认设置
的登录自动自定义验证**执行顺序文章来源:https://www.toymoban.com/news/detail-811285.html
- 在默认的页面登录的时候,sercurity会自动调用实现
PosswordEndcoder
接口的类中的encode
方法,进行密码的解析 - 然后sercurity接着调用实现
UserDetailsService
接口的实现类中的loadUserByUsername
方法,进行例如用户的查询 - 然后sercurity会接着调用实现
PosswordEndcoder
接口的类中的encode
方法,和matches进行库密码和表单密码的校验
文章来源地址https://www.toymoban.com/news/detail-811285.html
MySecurityConfiguration配置类的编写
@Configuration
@EnableWebSecurity
public class MySecurityConfiguration {
/**
* 创建Security过滤器链对象
* @return
*/
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity security) throws Exception {
// 登录配置类
Customizer<FormLoginConfigurer<HttpSecurity>> customizer = new Customizer<FormLoginConfigurer<HttpSecurity>>(){
@Override
public void customize(FormLoginConfigurer<HttpSecurity> configurer) {
//具体的认证配置
configurer
.loginPage("/login")
// .defaultSuccessUrl("/test")//默认跳转地址
// .successForwardUrl("/test") //认证成功后跳转地址
.successHandler(new MyAuthenticationsuccessHandler("/test",true))//设置认证成功后的处理代码逻辑。
.failureUrl("/loginfail")//登录失败跳转地址
;//设置登录页面访问地址。默认是/login。必须是get请求。自定义后提供控制器+视图
}
};
// 设置认证配置
security
.formLogin(customizer);
// 退出登录配置
Customizer<LogoutConfigurer<HttpSecurity>> logoutCustomizer = new Customizer<LogoutConfigurer<HttpSecurity>>() {
@Override
public void customize(LogoutConfigurer<HttpSecurity> configLoginout) {
configLoginout
.logoutUrl("/logout")//退出登录请求地址
.logoutSuccessUrl("/login")//退出登录成功以后跳转地址,默认是登录页面地址?logou
.logoutSuccessHandler(new MyLogOutsuccessHandler())//设置退出登录成功后的处理代码
.addLogoutHandler(new MyLogOutHandler())
;
}
};
// 设置登出配置
security.logout(logoutCustomizer);
security
.authorizeRequests()
.antMatchers("/login","/css/**","/image/**","/loginfail").permitAll() // 允许所有用户访问 /login 路径
.anyRequest().authenticated(); // 所有其他请求都需要认证
// 关闭CSRF功能
security.csrf().disable();
return security.build();
}
/**
* 创建一个passwordencoder类型bean对象
*/
@Bean
public PasswordEncoder passwordEncoder(){
//强散列密码解析器,构造方法可以传递整型参数,范围在4~31之间,数字越大强度越高,性能越低
return new BCryptPasswordEncoder();
}
}
MyAuthenticationsuccessHandler类用于处理认证成功的处理逻辑
//认证成功后的处理逻辑
public class MyAuthenticationsuccessHandler implements AuthenticationSuccessHandler {
// 登录成功后访问的地址
private String url;
// 是否是重定向
private boolean isRedirect;
public MyAuthenticationsuccessHandler( String url,boolean isRedirect){
this.url=url;
this.isRedirect=isRedirect;
}
/**
* 认证成功后具体的执行代码
* @param request
* @param response
* @param authentication 认证成功后的用户主体对象,包含个人登录的信息和权限列表
* @throws IOException
* @throws ServletException
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
if(isRedirect){
//重定向
response.sendRedirect(url);
}else
//请求转发
request.getRequestDispatcher(url).forward(request,response);
}
}
MyLogOutHandler(登出的一般做额外处理,比如保存会话中某些attribute到数据库)
public class MyLogOutHandler implements LogoutHandler {
/**
* 处理时逻辑
* @param request
* @param response
* @param authentication
*/
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
//一般做额外处理,比如保存会话中某些attribute到数据库
//比如记录日志
}
}
MyLogOutsuccessHandler(登出成功的处理逻辑)
public class MyLogOutsuccessHandler implements LogoutSuccessHandler {
/**
* 退出登录成功后的处理方案
*/
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("退出登录成功后的处理");
//销毁会话,清空缓存
request.getSession().invalidate();//销毁会话
authentication.setAuthenticated(false);//设置未登录状态
response.sendRedirect("/login");//进行重定向
}
}
到了这里,关于WebSocket和SpringSecurity的学习记录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!