目录
前言:
使用session实现登录
1 在用户登录时,将用户信息存储在session中,并将token和用户信息分别存储在一个全局的Map中
2 在用户登录或注销时,遍历Map中的所有token,并将新的用户信息发送给所有已登录的用户
3 在请求处理方法中获取token并从Map中获取用户信息
4 当用户注销时,清除session中对应的信息,并将新的用户信息发送给所有已登录的用户
5 当用户在其他设备或浏览器中登录时,使原有的token失效,并将新的用户信息发送给所有已登录的用户
全局map作用:
使用Spring框架提供的单例Bean实现全局存储。
通过ApplicationContext获取UserSession对象,并将token和用户信息存储在该对象中
session广播机制实现:
在登录成功后,将用户信息存储在session中,并将新的用户信息发送给所有已登录的客户端
WebSocketSessionManager类用于维护WebSocket连接和广播消息
WebSocketHandler类用于处理WebSocket连接和消息
在每个应用系统中,创建一个HttpSessionListener类,用来监听session的创建和销毁事件,并将session对象添加到SessionBroadcaster中。
在其他应用系统中,获取session对象时,先检查是否存在session,如果不存在,则跳转到登录页面。如果存在,则直接使用该session。
如果多个应用系统部署在同一个服务器上,可以通过以下方式实现多个应用系统之间共享session对象:
记录一个笔记,有点久了 忘掉了
用户登录时,将用户信息存储在session中,并生成一个全局唯一的token(可以使用UUID生成)。同时,将token和用户信息分别存储在一个全局的Map中,以便后续根据token查找用户信息。
当有用户登录或注销时,遍历Map中的所有token,并将新的用户信息发送给所有已登录的用户。
客户端在每个请求中,将token作为请求参数或请求头发送到服务器。
服务器在接收到请求时,先从请求中获取token,然后根据token从Map中获取用户信息。
如果Map中存在该token对应的用户信息,说明用户已经登录,直接响应请求。
如果Map中不存在该token对应的用户信息,说明用户未登录或已经注销,返回相应的提示信息。
当用户在其他设备或浏览器中登录时,系统会将原有的token失效,用户需要重新登录获取新的token。
用户注销时,系统需要清除session中对应的用户信息和token,并将新的用户信息发送给所有已登录的用户
String token = UUID.randomUUID().toString(); // 生成唯一的token
session.setAttribute(token, user); // 将用户信息存入session中
userMap.put(token, user); // 将token和用户信息存储在Map中
for (String key : userMap.keySet()) { User user = userMap.get(key); // 将新的用户信息发送给所有已登录的用户 // ... }
String token = request.getHeader("token"); // 获取token User user = userMap.get(token); // 获取用户信息 if (user != null) { // 用户已登录,处理请求 } else { // 用户未登录或已注销,返回提示信息 } ----request是从请求头获取的token, 这里是前端传值, 前端在请求头添加token
HttpServletRequest request 后端通过 request.getHeader("token") 获取信息
session.removeAttribute(token); // 清除用户信息 userMap.remove(token); // 清除token信息 for (String key : userMap.keySet()) { User user = userMap.get(key); // 将新的用户信息发送给所有已登录的用户 // ... }
User oldUser = userMap.remove(token); // 清除原有的token信息 session.removeAttribute(token); // 清除原有的用户信息 userMap.put(newToken, oldUser); // 将新的token和原有的用户信息存入Map中 session.setAttribute(newToken, oldUser); // 将原有的用户信息存入新的session中 for (String key : userMap.keySet()) { User user = userMap.get(key); // 将新的用户信息发送给所有已登录的用户 // ... }
全局Map的作用是将token和用户信息进行对应存储,以便后续根据token查找用户信息。实现方式可以是使用一个静态变量来存储Map对象,也可以使用Spring框架提供的单例Bean实现全局存储。
以下是使用静态变量来存储全局Map对象的示例代码:
public class UserSession {
private static Map userMap = new ConcurrentHashMap<>();
public static User getUser(String token) {
return userMap.get(token);
}
public static void setUser(String token, User user) {
userMap.put(token, user);
}
public static void removeUser(String token) {
userMap.remove(token);
}
}
使用了ConcurrentHashMap来存储全局Map对象,保证了线程安全。
@Component
@Scope(value = "singleton")
public class UserSession {
private Map userMap = new ConcurrentHashMap<>();
public User getUser(String token) {
return userMap.get(token);
}
public void setUser(String token, User user) {
userMap.put(token, user);
}
public void removeUser(String token) {
userMap.remove(token);
}
}
获取bean对象以后,在使用里面的方法,步骤同上面全局map一样
String token = UUID.randomUUID().toString(); // 生成唯一的token
User user = userService.getUserByUsernameAndPassword(username, password); // 获取用户信息
UserSession userSession = applicationContext.getBean(UserSession.class); // 获取UserSession对象
userSession.setUser(token, user); // 将token和用户信息存储在UserSession对象中
// 将token返回给客户端
return Result.success("登录成功").setData(token);
要实现session的广播机制,可以使用WebSocket技术,客户端与服务器建立WebSocket连接后,服务器可以通过WebSocket向所有客户端发送消息。在单点登录场景下,可以在用户登录成功后,将用户信息存储在session中,并在WebSocket广播中发送新的用户信息给所有已登录的客户端,以保证其他客户端可以及时更新用户信息。
在单点登录的场景中,用户只需要登录一次,就可以访问多个应用系统。为了实现这个功能,我们需要在所有的应用系统中共享session。在Java语言中,可以使用session广播机制来实现。当用户在一个应用系统中登录成功后,将session广播给其他应用系统,其他应用系统就可以获取到该session了。
String token = UUID.randomUUID().toString(); // 生成唯一的token
session.setAttribute(token, user); // 将用户信息存储在session中
// 将新的用户信息发送给所有已登录的客户端
WebSocketSessionManager.broadcastMessage(user);
// 将token返回给客户端
return Result.success("登录成功").setData(token);
public class WebSocketSessionManager {
private static final List sessions = new ArrayList<>();
public static void addSession(WebSocketSession session) {
sessions.add(session);
}
public static void removeSession(WebSocketSession session) {
sessions.remove(session);
}
public static void broadcastMessage(User user) {
for (WebSocketSession session : sessions) {
if (session.isOpen()) {
try {
session.sendMessage(new TextMessage("new user: " + user.getUsername()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
上面代码, WebSocketSessionManager类用于维护WebSocket连接和广播消息。addSession和removeSession方法用于添加和移除WebSocketSession对象,broadcastMessage方法用于向所有已登录的客户端广播新的用户信息。
@Component
public class WebSocketHandler extends TextWebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
// 添加WebSocketSession对象
WebSocketSessionManager.addSession(session);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// 处理WebSocket消息
if ("get_user_info".equals(message.getPayload())) {
User user = (User) session.getAttributes().get("user"); // 从session中获取用户信息
if (user != null) {
TextMessage userInfoMessage = new TextMessage("user: " + user.toString()); // 将用户信息转化为消息
session.sendMessage(userInfoMessage); // 将用户信息发送给客户端
}
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
// 移除WebSocketSession对象
WebSocketSessionManager.removeSession(session);
}
}
WebSocketHandler类用于处理WebSocket连接和消息。在afterConnectionEstablished方法中,添加WebSocketSession对象;在handleTextMessage方法中,处理WebSocket消息;在afterConnectionClosed方法中,移除WebSocketSession对象。
handleTextMessage
方法中处理接收到的文本消息。然后并把session信息发给其他客户端
public class SessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent event) {
HttpSession session = event.getSession();
SessionBroadcaster.add(session);
}
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
SessionBroadcaster.remove(session);
}
}
我们实现了HttpSessionListener接口,并重写了sessionCreated和sessionDestroyed方法。当session创建时,将其添加到SessionBroadcaster中。当session销毁时,将其从SessionBroadcaster中移除。
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("username") == null) {
response.sendRedirect("login.jsp");
} else {
String username = (String) session.getAttribute("username");
// 使用session对象
}
我们使用getSession(false)
方法来获取session对象,如果session不存在,则返回null。如果session存在,则使用getAttribute("username")
方法来获取用户名。如果用户名为空,则跳转到登录页面。否则,直接使用该session对象。
使用同一个域名。如果多个应用系统使用同一个域名,浏览器会将cookie发送给同一个域名,从而实现session共享。
使用同一个上下文路径。如果多个应用系统使用同一个上下文路径,浏览器会将cookie发送给同一个上下文路径,从而实现session共享。
使用同一个session存储方式。如果多个应用系统使用同一个session存储方式,比如使用同一个数据库或者同一个缓存服务器,就可以实现session共享。
使用session复制。如果多个应用系统使用session复制,就可以将session对象复制到其他应用系统中,从而实现session共享。