[Java实现单点登录session ]

目录

前言: 

使用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实现登录

  • 用户登录时,将用户信息存储在session中,并生成一个全局唯一的token(可以使用UUID生成)。同时,将token和用户信息分别存储在一个全局的Map中,以便后续根据token查找用户信息。

  • 当有用户登录或注销时,遍历Map中的所有token,并将新的用户信息发送给所有已登录的用户。

  • 客户端在每个请求中,将token作为请求参数或请求头发送到服务器。

  • 服务器在接收到请求时,先从请求中获取token,然后根据token从Map中获取用户信息。

  • 如果Map中存在该token对应的用户信息,说明用户已经登录,直接响应请求。

  • 如果Map中不存在该token对应的用户信息,说明用户未登录或已经注销,返回相应的提示信息。

  • 当用户在其他设备或浏览器中登录时,系统会将原有的token失效,用户需要重新登录获取新的token。

  • 用户注销时,系统需要清除session中对应的用户信息和token,并将新的用户信息发送给所有已登录的用户

 
  

1 在用户登录时,将用户信息存储在session中,并将token和用户信息分别存储在一个全局的Map中

String token = UUID.randomUUID().toString(); // 生成唯一的token
session.setAttribute(token, user); // 将用户信息存入session中
userMap.put(token, user); // 将token和用户信息存储在Map中
 

2 在用户登录或注销时,遍历Map中的所有token,并将新的用户信息发送给所有已登录的用户

for (String key : userMap.keySet()) {
    User user = userMap.get(key);
    // 将新的用户信息发送给所有已登录的用户
    // ...
}

3 在请求处理方法中获取token并从Map中获取用户信息

String token = request.getHeader("token"); // 获取token
User user = userMap.get(token); // 获取用户信息
if (user != null) {
    // 用户已登录,处理请求
} else {
    // 用户未登录或已注销,返回提示信息
}
----

request是从请求头获取的token, 这里是前端传值, 前端在请求头添加token

HttpServletRequest request   后端通过  request.getHeader("token") 获取信息

4 当用户注销时,清除session中对应的信息,并将新的用户信息发送给所有已登录的用户

session.removeAttribute(token); // 清除用户信息
userMap.remove(token); // 清除token信息
for (String key : userMap.keySet()) {
    User user = userMap.get(key);
    // 将新的用户信息发送给所有已登录的用户
    // ...
}

5 当用户在其他设备或浏览器中登录时,使原有的token失效,并将新的用户信息发送给所有已登录的用户

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作用:

全局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);
    }
}

使用Spring框架提供的单例Bean实现全局存储。

使用了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);
    }
}

通过ApplicationContext获取UserSession对象,并将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广播机制实现:

要实现session的广播机制,可以使用WebSocket技术,客户端与服务器建立WebSocket连接后,服务器可以通过WebSocket向所有客户端发送消息。在单点登录场景下,可以在用户登录成功后,将用户信息存储在session中,并在WebSocket广播中发送新的用户信息给所有已登录的客户端,以保证其他客户端可以及时更新用户信息。

在单点登录的场景中,用户只需要登录一次,就可以访问多个应用系统。为了实现这个功能,我们需要在所有的应用系统中共享session。在Java语言中,可以使用session广播机制来实现。当用户在一个应用系统中登录成功后,将session广播给其他应用系统,其他应用系统就可以获取到该session了。

在登录成功后,将用户信息存储在session中,并将新的用户信息发送给所有已登录的客户端

String token = UUID.randomUUID().toString(); // 生成唯一的token
session.setAttribute(token, user); // 将用户信息存储在session中
// 将新的用户信息发送给所有已登录的客户端
WebSocketSessionManager.broadcastMessage(user);
// 将token返回给客户端
return Result.success("登录成功").setData(token);
  1. WebSocketSessionManager类用于维护WebSocket连接和广播消息

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方法用于向所有已登录的客户端广播新的用户信息。

  1. WebSocketHandler类用于处理WebSocket连接和消息

@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信息发给其他客户端

在每个应用系统中,创建一个HttpSessionListener类,用来监听session的创建和销毁事件,并将session对象添加到SessionBroadcaster中。

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中移除。
  1. 在其他应用系统中,获取session对象时,先检查是否存在session,如果不存在,则跳转到登录页面。如果存在,则直接使用该session。

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对象。

如果多个应用系统部署在同一个服务器上,可以通过以下方式实现多个应用系统之间共享session对象:

  • 使用同一个域名。如果多个应用系统使用同一个域名,浏览器会将cookie发送给同一个域名,从而实现session共享。

  • 使用同一个上下文路径。如果多个应用系统使用同一个上下文路径,浏览器会将cookie发送给同一个上下文路径,从而实现session共享。

  • 使用同一个session存储方式。如果多个应用系统使用同一个session存储方式,比如使用同一个数据库或者同一个缓存服务器,就可以实现session共享。

  • 使用session复制。如果多个应用系统使用session复制,就可以将session对象复制到其他应用系统中,从而实现session共享。

你可能感兴趣的:(粉丝栏,java,开发语言)