Добавил поле authNonce(Вместо SessionPWD) при запросе авторизации
This commit is contained in:
AidarKC 2025-12-11 16:22:12 +03:00
parent dbf1f22bac
commit 80ffba545a
4 changed files with 37 additions and 31 deletions

View File

@ -27,11 +27,16 @@ public class ConnectionContext {
private String sessionId;
/**
* Временный секрет шага 1, который используется на шаге 2 и хранится в БД,
* а после успешной авторизации настоящий секрет сессии.
* Секрет сессии (то, что хранится в active_sessions.session_pwd).
*/
private String sessionPwd;
/**
* Одноразовый nonce, выданный на шаге 1 (AuthChallenge),
* используется на шаге 2 для проверки подписи.
*/
private String authNonce;
/**
* Текущий статус аутентификации.
* См. константы AUTH_STATUS_*
@ -100,6 +105,16 @@ public class ConnectionContext {
this.sessionPwd = sessionPwd;
}
// --- authNonce ---
public String getAuthNonce() {
return authNonce;
}
public void setAuthNonce(String authNonce) {
this.authNonce = authNonce;
}
// --- auth status ---
public int getAuthenticationStatus() {
@ -124,6 +139,7 @@ public class ConnectionContext {
sessionId = null;
sessionPwd = null;
authNonce = null;
authenticationStatus = AUTH_STATUS_NONE;
wsSession = null;

View File

@ -3,9 +3,9 @@ package server.logic.ws_protocol.JSON.entyties.Auth;
import server.logic.ws_protocol.JSON.entyties.Net_Request;
/**
* Шаг 1 авторизации: запрос выдачи временного пароля сессии (sessionPwd).
* Шаг 1 авторизации: запрос выдачи одноразового nonce (authNonce).
*
* Клиент по логину просит сервер сгенерировать случайный секрет sessionPwd,
* Клиент по логину просит сервер сгенерировать случайный authNonce,
* который будет использован на втором шаге при подписи.
*
* Формат входящего JSON:
@ -23,7 +23,7 @@ import server.logic.ws_protocol.JSON.entyties.Net_Request;
* "requestId": "...",
* "status": 200,
* "payload": {
* "sessionPwd": "base64-строка-от-32-байт"
* "authNonce": "base64-строка-от-32-байт"
* }
* }
*/
@ -40,4 +40,4 @@ public class Net_AuthChallenge_Request extends Net_Request {
public void setLogin(String login) {
this.login = login;
}
}
}

View File

@ -71,8 +71,8 @@ public class Net_AuthChallenge_Handler implements JsonMessageHandler {
RANDOM.nextBytes(buf);
String authNonce = Base64.getUrlEncoder().withoutPadding().encodeToString(buf);
// Используем поле sessionPwd в контексте как хранилище challenge (authNonce) до шага 2
ctx.setSessionPwd(authNonce);
// Сохраняем challenge в отдельном поле authNonce
ctx.setAuthNonce(authNonce);
// 5) Формируем ответ
Net_AuthChallenge_Response resp = new Net_AuthChallenge_Response();

View File

@ -35,7 +35,8 @@ import java.util.Base64;
* "AUTHORIFICATED:" + timeMs + authNonce)
* - clientInfo (опционально, до 50 символов)
*
* authNonce клиент получил на шаге 1 (AuthChallenge).
* authNonce клиент получил на шаге 1 (AuthChallenge) и сервер
* сохранил его в ctx.authNonce.
*
* При успехе:
* - создаётся запись ActiveSession в БД;
@ -59,27 +60,19 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
public Net_Response handle(Net_Request baseReq, ConnectionContext ctx) throws Exception {
Net_CreateAuthSession_Request req = (Net_CreateAuthSession_Request) baseReq;
// --- базовые проверки контекста ---
if (ctx == null || ctx.getSolanaUser() == null || ctx.getSessionPwd() == null) {
// --- базовые проверки контекста шага 1 ---
if (ctx == null
|| ctx.getSolanaUser() == null
|| ctx.getAuthNonce() == null
|| ctx.getAuthenticationStatus() != ConnectionContext.AUTH_STATUS_AUTH_IN_PROGRESS) {
Net_Response err = NetExceptionResponseFactory.error(
req,
WireCodes.Status.BAD_REQUEST,
"NO_STEP1_CONTEXT",
"Шаг 1 авторизации не был корректно выполнен для данного соединения"
);
WsConnectionUtils.closeConnection(ctx, 4001, "Auth failed: no step1 context");
return err;
}
// Ожидаем, что перед этим был AuthChallenge и статус = AUTH_IN_PROGRESS
if (ctx.getAuthenticationStatus() != ConnectionContext.AUTH_STATUS_AUTH_IN_PROGRESS) {
Net_Response err = NetExceptionResponseFactory.error(
req,
WireCodes.Status.BAD_REQUEST,
"BAD_AUTH_FLOW_STATE",
"Неожиданное состояние авторификации для данного соединения"
);
WsConnectionUtils.closeConnection(ctx, 4001, "Auth failed: bad auth flow state");
WsConnectionUtils.closeConnection(ctx, 4001, "Auth failed: no step1 context or bad auth state");
return err;
}
@ -170,8 +163,8 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
return err;
}
// --- authNonce (challenge) мы сохранили в ctx.sessionPwd на шаге 1 ---
String authNonce = ctx.getSessionPwd();
// --- authNonce (challenge) мы сохранили в ctx.authNonce на шаге 1 ---
String authNonce = ctx.getAuthNonce();
// --- собираем строку для подписи: "AUTHORIFICATED:" + timeMs + authNonce ---
String preimageStr = "AUTHORIFICATED:" + timeMs + authNonce;
@ -201,16 +194,12 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
String clientIp = null;
if (wsSession != null) {
// стандартный метод получения IP
clientIp = ClientInfoService.extractClientIp(wsSession);
// Дёргаем запрос геолокации (ничего не сохраняем в сессию),
// нужно лишь для того, чтобы данные попали в кэш сервера.
if (clientIp != null && !clientIp.isBlank()) {
try {
GeoLookupService.resolveCountryCityOrIpWithCache(clientIp);
} catch (Exception e) {
// геолокация не критична, можно тихо залогировать на debug
log.debug("Geo lookup failed for ip={}", clientIp, e);
}
}
@ -257,7 +246,8 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
// --- обновляем контекст ---
ctx.setActiveSession(activeSession);
ctx.setSessionId(sessionId);
ctx.setSessionPwd(newSessionPwd); // теперь в контексте хранится секрет сессии, а не authNonce
ctx.setSessionPwd(newSessionPwd); // теперь в контексте хранится секрет сессии
ctx.setAuthNonce(null); // одноразовый nonce больше не нужен
ctx.setAuthenticationStatus(ConnectionContext.AUTH_STATUS_USER);
ActiveConnectionsRegistry.getInstance().register(ctx);