SHA256
04 12 25 Версия авторификации где сервер выдовал сессион Ид
This commit is contained in:
+123
@@ -0,0 +1,123 @@
|
||||
package server.logic.ws_protocol.JSON;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* Реестр активных подключений (только авторизованные).
|
||||
*.
|
||||
* Позволяет:
|
||||
* - получить ConnectionContext по sessionId;
|
||||
* - получить все активные подключения пользователя по loginId;
|
||||
* - удалить подключение при закрытии WebSocket.
|
||||
*.
|
||||
* найти все подключения пользователя:
|
||||
* var set = ActiveConnectionsRegistry.getInstance().getByLoginId(loginId);
|
||||
*.
|
||||
* найти конкретное подключение по sessionId:
|
||||
* ConnectionContext ctx = ActiveConnectionsRegistry.getInstance().getBySessionId(sessionId);
|
||||
* Session ws = ctx != null ? ctx.getWsSession() : null;
|
||||
*/
|
||||
|
||||
public final class ActiveConnectionsRegistry {
|
||||
|
||||
private static final ActiveConnectionsRegistry INSTANCE = new ActiveConnectionsRegistry();
|
||||
|
||||
public static ActiveConnectionsRegistry getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private ActiveConnectionsRegistry() {
|
||||
// singleton
|
||||
}
|
||||
|
||||
// sessionId -> ConnectionContext
|
||||
private final ConcurrentHashMap<Long, ConnectionContext> bySessionId = new ConcurrentHashMap<>();
|
||||
|
||||
// loginId -> множество ConnectionContext для этого пользователя
|
||||
private final ConcurrentHashMap<Long, Set<ConnectionContext>> byLoginId = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Зарегистрировать авторизованное подключение.
|
||||
* Ожидается, что в ctx уже выставлены loginId и sessionId.
|
||||
*/
|
||||
public void register(ConnectionContext ctx) {
|
||||
if (ctx == null) return;
|
||||
|
||||
Long sessionId = ctx.getSessionId();
|
||||
Long loginId = ctx.getLoginId();
|
||||
|
||||
if (sessionId == null || loginId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
bySessionId.put(sessionId, ctx);
|
||||
|
||||
byLoginId
|
||||
.computeIfAbsent(loginId, id -> new CopyOnWriteArraySet<>())
|
||||
.add(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Удалить подключение по контексту (например, при onClose).
|
||||
*/
|
||||
public void remove(ConnectionContext ctx) {
|
||||
if (ctx == null) return;
|
||||
|
||||
Long sessionId = ctx.getSessionId();
|
||||
Long loginId = ctx.getLoginId();
|
||||
|
||||
if (sessionId != null) {
|
||||
bySessionId.remove(sessionId);
|
||||
}
|
||||
|
||||
if (loginId != null) {
|
||||
Set<ConnectionContext> set = byLoginId.get(loginId);
|
||||
if (set != null) {
|
||||
set.remove(ctx);
|
||||
if (set.isEmpty()) {
|
||||
byLoginId.remove(loginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Удалить подключение по sessionId.
|
||||
*/
|
||||
public void removeBySessionId(long sessionId) {
|
||||
ConnectionContext ctx = bySessionId.remove(sessionId);
|
||||
if (ctx != null) {
|
||||
Long loginId = ctx.getLoginId();
|
||||
if (loginId != null) {
|
||||
Set<ConnectionContext> set = byLoginId.get(loginId);
|
||||
if (set != null) {
|
||||
set.remove(ctx);
|
||||
if (set.isEmpty()) {
|
||||
byLoginId.remove(loginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить контекст по sessionId.
|
||||
*/
|
||||
public ConnectionContext getBySessionId(long sessionId) {
|
||||
return bySessionId.get(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить все активные подключения пользователя по loginId.
|
||||
*/
|
||||
public Set<ConnectionContext> getByLoginId(long loginId) {
|
||||
Set<ConnectionContext> set = byLoginId.get(loginId);
|
||||
if (set == null) {
|
||||
return Set.of();
|
||||
}
|
||||
// CopyOnWriteArraySet безопасно отдавать как есть
|
||||
return set;
|
||||
}
|
||||
}
|
||||
+18
@@ -1,5 +1,6 @@
|
||||
package server.logic.ws_protocol.JSON;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import shine.db.entities.SolanaUser;
|
||||
import shine.db.entities.ActiveSession;
|
||||
|
||||
@@ -24,6 +25,22 @@ public class ConnectionContext {
|
||||
|
||||
private int authenticationStatus = AUTH_STATUS_NONE;
|
||||
|
||||
/**
|
||||
* WebSocket-сессия Jetty для данного подключения.
|
||||
* Нужна, чтобы через ConnectionContext можно было отправлять сообщения клиенту.
|
||||
*/
|
||||
private Session wsSession;
|
||||
|
||||
// --- WebSocket Session ---
|
||||
|
||||
public Session getWsSession() {
|
||||
return wsSession;
|
||||
}
|
||||
|
||||
public void setWsSession(Session wsSession) {
|
||||
this.wsSession = wsSession;
|
||||
}
|
||||
|
||||
// --- SolanaUser / ActiveSession ---
|
||||
|
||||
public SolanaUser getSolanaUser() {
|
||||
@@ -96,6 +113,7 @@ public class ConnectionContext {
|
||||
sessionPwd = null;
|
||||
|
||||
authenticationStatus = AUTH_STATUS_NONE;
|
||||
wsSession = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ import java.util.Map;
|
||||
/**
|
||||
* JsonHandlerRegistry — единое место, где руками регистрируются
|
||||
* JSON-операции: op → handler и op → requestClass.
|
||||
*
|
||||
*.
|
||||
* Если нужно добавить новый запрос:
|
||||
* 1) создаёшь класс NetXXXRequest / NetXXXResponse,
|
||||
* 2) создаёшь JsonMessageHandler (NetXXXHandler),
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* JsonInboundProcessor — обработка JSON-сообщений.
|
||||
*
|
||||
*.
|
||||
* 1) Парсит общий пакет (op, requestId,...).
|
||||
* 2) По op выбирает класс запроса и хэндлер.
|
||||
* 3) Маппит JSON → NetRequest через ObjectMapper.
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import server.logic.ws_protocol.JSON.entyties.NetRequest;
|
||||
|
||||
/**
|
||||
* Шаг 2 авторизации: клиент подтверждает владение ключом.
|
||||
*
|
||||
*.
|
||||
* JSON:
|
||||
* {
|
||||
* "op": "AuthSessionNewStep2",
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import server.logic.ws_protocol.JSON.entyties.NetResponse;
|
||||
|
||||
/**
|
||||
* Ответ на AuthSessionNewStep2.
|
||||
*
|
||||
*.
|
||||
* Успешный JSON:
|
||||
* {
|
||||
* "op": "AuthSessionNewStep2",
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import server.logic.ws_protocol.JSON.entyties.NetRequest;
|
||||
|
||||
/**
|
||||
* Запрос SessionRefresh.
|
||||
*
|
||||
*.
|
||||
* JSON (payload):
|
||||
* {
|
||||
* "sessionId": 123,
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import server.logic.ws_protocol.JSON.entyties.NetResponse;
|
||||
|
||||
/**
|
||||
* Успешный ответ на SessionRefresh.
|
||||
*
|
||||
*.
|
||||
* Дополнительных полей нет, достаточно status=200 и (опционально) пустого payload.
|
||||
*/
|
||||
public class NetSessionRefreshResponse extends NetResponse {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package server.logic.ws_protocol.JSON.entyties;
|
||||
/**
|
||||
* Базовый класс для всех событий (event).
|
||||
* Общие поля: op и payload.
|
||||
*
|
||||
*.
|
||||
* Формат JSON (event):
|
||||
* {
|
||||
* "op": "...",
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package server.logic.ws_protocol.JSON.entyties;
|
||||
|
||||
/**
|
||||
* Ответ с ошибкой (любой отказ).
|
||||
*
|
||||
*.
|
||||
* В payload будет:
|
||||
* {
|
||||
* "code": "...",
|
||||
|
||||
+2
-2
@@ -2,9 +2,9 @@ package server.logic.ws_protocol.JSON.entyties;
|
||||
|
||||
/**
|
||||
* Базовый класс для всех запросов (client → server).
|
||||
*
|
||||
*.
|
||||
* Наследуется от NetEvent и добавляет requestId.
|
||||
*
|
||||
*.
|
||||
* Формат JSON (request):
|
||||
* {
|
||||
* "op": "...",
|
||||
|
||||
+2
-2
@@ -2,9 +2,9 @@ package server.logic.ws_protocol.JSON.entyties;
|
||||
|
||||
/**
|
||||
* Базовый класс для всех ответов (server → client).
|
||||
*
|
||||
*.
|
||||
* Наследуется от NetRequest и добавляет status.
|
||||
*
|
||||
*.
|
||||
* Формат JSON (response):
|
||||
* {
|
||||
* "op": "...",
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import server.logic.ws_protocol.JSON.entyties.NetRequest;
|
||||
|
||||
/**
|
||||
* Запрос AddUser.
|
||||
*
|
||||
*.
|
||||
* Ожидаемый JSON:
|
||||
* {
|
||||
* "op": "AddUser",
|
||||
|
||||
+5
-1
@@ -2,6 +2,7 @@ package server.logic.ws_protocol.JSON.handlers.auth;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import server.logic.ws_protocol.JSON.ActiveConnectionsRegistry;
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import server.logic.ws_protocol.JSON.entyties.NetRequest;
|
||||
import server.logic.ws_protocol.JSON.entyties.NetResponse;
|
||||
@@ -22,7 +23,7 @@ import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* Шаг 2 авторизации: проверка подписи и создание сессии.
|
||||
*
|
||||
*.
|
||||
* Клиент присылает:
|
||||
* - loginId
|
||||
* - sigNum (0 или 1)
|
||||
@@ -165,6 +166,9 @@ public class NetAuthSessionNewStep2Handler implements JsonMessageHandler {
|
||||
ctx.setSessionId(sessionId);
|
||||
ctx.setAuthenticationStatus(ConnectionContext.AUTH_STATUS_USER);
|
||||
|
||||
// Регистрируем это подключение в глобальном реестре активных соединений
|
||||
ActiveConnectionsRegistry.getInstance().register(ctx);
|
||||
|
||||
// --- формируем ответ ---
|
||||
NetAuthSessionNewStep2Response resp = new NetAuthSessionNewStep2Response();
|
||||
resp.setOp(req.getOp());
|
||||
|
||||
+4
@@ -2,6 +2,7 @@ package server.logic.ws_protocol.JSON.handlers.auth;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import server.logic.ws_protocol.JSON.ActiveConnectionsRegistry;
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import server.logic.ws_protocol.JSON.entyties.NetRequest;
|
||||
import server.logic.ws_protocol.JSON.entyties.NetResponse;
|
||||
@@ -108,6 +109,9 @@ public class NetSessionRefreshHandler implements JsonMessageHandler {
|
||||
ctx.setSessionId(sessionId);
|
||||
ctx.setSessionPwd(sessionPwd);
|
||||
ctx.setAuthenticationStatus(ConnectionContext.AUTH_STATUS_USER);
|
||||
|
||||
// Регистрируем это подключение в глобальном реестре активных соединений
|
||||
ActiveConnectionsRegistry.getInstance().register(ctx);
|
||||
}
|
||||
|
||||
// И возвращаем OK без доп. полей (payload будет {}).
|
||||
|
||||
@@ -2,11 +2,11 @@ package server.logic.ws_protocol;
|
||||
|
||||
/**
|
||||
* WireCodes — константы бинарного протокола поверх WebSocket.
|
||||
*
|
||||
*.
|
||||
* Формат входящего сообщения:
|
||||
* [4] int opCode (big-endian)
|
||||
* [*] payload
|
||||
*
|
||||
*.
|
||||
* Ответ сервера:
|
||||
* ровно [4] int statusCode (big-endian)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user