feat(online): implement IchniOnline API integration with BestHTTP
- Add BestHTTP reference to IchniOnline.asmdef - Create ApiClient.cs: HTTP singleton with JWT auto-injection - Create ApiResponse.cs: ResponseCode enum, GlobalResponse<T>, ApiResult<T> - Create AuthDtos.cs: ThirdPartyLoginRequestDto, LoginRequestDto, RegisterRequestDto, LoginResponseDto, UserResponseDto - Create AuthService.cs: TapTap/password/register/logout flows with events - Extend LoginCacheData.cs: JWT + server user data fields - Extend LoginCacheManager.cs: SaveAuthSession, ClearSession, HasValidSession - Extend ThirdPartyServiceManager.cs: OnLoginWithToken event for AuthService - Update LoginPage.cs: Use AuthService with loading states and null-safe callbacks - Update StartUIPage.cs: Use HasValidSession for session check Fixes post-review: - LoginPage: Add null check for Register success (response may be null) - AuthService: Add try/catch around TapTap login API call
This commit is contained in:
327
Assets/Scripts/Online/Logic/AuthService.cs
Normal file
327
Assets/Scripts/Online/Logic/AuthService.cs
Normal file
@@ -0,0 +1,327 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using IchniOnline.Online.Network;
|
||||
using IchniOnline.Online.Network.Models;
|
||||
using TapSDK.Login;
|
||||
using UnityEngine;
|
||||
|
||||
namespace IchniOnline.Online.Network.Models
|
||||
{
|
||||
[Serializable]
|
||||
public class SessionKeyResponseDto
|
||||
{
|
||||
public string SessionKey;
|
||||
public long ExpiresAt;
|
||||
}
|
||||
}
|
||||
|
||||
namespace IchniOnline.Online.Logic
|
||||
{
|
||||
/// <summary>
|
||||
/// Authentication orchestration service that coordinates TapTap login,
|
||||
/// password login, registration, and logout flows.
|
||||
/// Pure orchestration — no UI state management. Results are delivered via events.
|
||||
/// </summary>
|
||||
public static class IchniOnlineAuthService
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录成功时触发,参数为服务端返回的登录响应(Register 成功时可能为 null)
|
||||
/// </summary>
|
||||
public static event Action<LoginResponseDto> OnLoginSuccess;
|
||||
|
||||
/// <summary>
|
||||
/// 登录失败时触发,参数为错误信息
|
||||
/// </summary>
|
||||
public static event Action<string> OnLoginFailed;
|
||||
|
||||
/// <summary>
|
||||
/// 登录被用户取消时触发
|
||||
/// </summary>
|
||||
public static event Action OnLoginCanceled;
|
||||
|
||||
/// <summary>
|
||||
/// 是否正在进行登录流程,用于防止并发登录请求
|
||||
/// </summary>
|
||||
public static bool IsLoggingIn { get; private set; }
|
||||
|
||||
#region TapTap Login
|
||||
|
||||
/// <summary>
|
||||
/// 使用 TapTap 登录的完整流程:
|
||||
/// TapTap SDK → 第三方登录 API → JWT → 缓存 → 事件
|
||||
/// </summary>
|
||||
public static async void LoginWithTapTap()
|
||||
{
|
||||
if (IsLoggingIn)
|
||||
{
|
||||
Debug.LogWarning("[IchniOnlineAuthService] 已有登录流程正在进行中");
|
||||
return;
|
||||
}
|
||||
|
||||
IsLoggingIn = true;
|
||||
|
||||
Action<TapTapAccount> onSuccess = null;
|
||||
Action onCanceled = null;
|
||||
Action<string> onFailed = null;
|
||||
|
||||
onSuccess = async account =>
|
||||
{
|
||||
UnsubscribeTapTapEvents(onSuccess, onCanceled, onFailed);
|
||||
|
||||
if (account?.accessToken == null)
|
||||
{
|
||||
IsLoggingIn = false;
|
||||
OnLoginFailed?.Invoke("TapTap 登录成功但 accessToken 为空");
|
||||
return;
|
||||
}
|
||||
|
||||
var dto = new ThirdPartyLoginRequestDto
|
||||
{
|
||||
Token = account.accessToken.kid,
|
||||
TokenType = account.accessToken.tokenType,
|
||||
MacKey = account.accessToken.macKey,
|
||||
MacAlgorithm = account.accessToken.macAlgorithm
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var result = await IchniOnlineApiClient.Instance.PostAsync<LoginResponseDto>("/api/auth/third-party/login", dto);
|
||||
|
||||
IsLoggingIn = false;
|
||||
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
LoginCacheManager.SaveAuthSession(result.Data.Token, result.Data);
|
||||
IchniOnlineApiClient.Instance.JwtToken = result.Data.Token;
|
||||
OnLoginSuccess?.Invoke(result.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMessage = $"第三方登录 API 失败: {result.Message}";
|
||||
if (!string.IsNullOrEmpty(result.ErrorDetail))
|
||||
errorMessage += $" ({result.ErrorDetail})";
|
||||
OnLoginFailed?.Invoke(errorMessage);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsLoggingIn = false;
|
||||
Debug.LogError($"[IchniOnlineAuthService] TapTap 登录 API 异常: {ex}");
|
||||
OnLoginFailed?.Invoke($"TapTap 登录 API 异常: {ex.Message}");
|
||||
}
|
||||
};
|
||||
|
||||
onCanceled = () =>
|
||||
{
|
||||
UnsubscribeTapTapEvents(onSuccess, onCanceled, onFailed);
|
||||
IsLoggingIn = false;
|
||||
OnLoginCanceled?.Invoke();
|
||||
};
|
||||
|
||||
onFailed = errorMessage =>
|
||||
{
|
||||
UnsubscribeTapTapEvents(onSuccess, onCanceled, onFailed);
|
||||
IsLoggingIn = false;
|
||||
OnLoginFailed?.Invoke($"TapTap 登录失败: {errorMessage}");
|
||||
};
|
||||
|
||||
ThirdPartyServiceManager.Instance.OnLoginSuccess += onSuccess;
|
||||
ThirdPartyServiceManager.Instance.OnLoginCanceled += onCanceled;
|
||||
ThirdPartyServiceManager.Instance.OnLoginFailed += onFailed;
|
||||
|
||||
ThirdPartyServiceManager.Instance.StartTapTapLogin();
|
||||
}
|
||||
|
||||
private static void UnsubscribeTapTapEvents(
|
||||
Action<TapTapAccount> onSuccess,
|
||||
Action onCanceled,
|
||||
Action<string> onFailed)
|
||||
{
|
||||
if (ThirdPartyServiceManager.Instance != null)
|
||||
{
|
||||
ThirdPartyServiceManager.Instance.OnLoginSuccess -= onSuccess;
|
||||
ThirdPartyServiceManager.Instance.OnLoginCanceled -= onCanceled;
|
||||
ThirdPartyServiceManager.Instance.OnLoginFailed -= onFailed;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Password Login
|
||||
|
||||
/// <summary>
|
||||
/// 使用用户名和密码登录的完整流程:
|
||||
/// 获取 session-key → XOR 加密密码 → 登录 API → JWT → 缓存 → 事件
|
||||
/// </summary>
|
||||
public static async void LoginWithPassword(string username, string password)
|
||||
{
|
||||
if (IsLoggingIn)
|
||||
{
|
||||
Debug.LogWarning("[IchniOnlineAuthService] 已有登录流程正在进行中");
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
|
||||
{
|
||||
OnLoginFailed?.Invoke("用户名或密码不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
IsLoggingIn = true;
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 获取 session-key
|
||||
var sessionResult = await IchniOnlineApiClient.Instance.GetAsync<SessionKeyResponseDto>("/api/auth/session-key");
|
||||
if (!sessionResult.IsSuccess)
|
||||
{
|
||||
IsLoggingIn = false;
|
||||
string errorMessage = $"获取 session-key 失败: {sessionResult.Message}";
|
||||
if (!string.IsNullOrEmpty(sessionResult.ErrorDetail))
|
||||
errorMessage += $" ({sessionResult.ErrorDetail})";
|
||||
OnLoginFailed?.Invoke(errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
string sessionKey = sessionResult.Data.SessionKey;
|
||||
|
||||
// 2. XOR 加密密码
|
||||
string encryptedPassword = EncryptPassword(password, sessionKey);
|
||||
|
||||
// 3. 调用登录 API
|
||||
var loginDto = new LoginRequestDto
|
||||
{
|
||||
Username = username,
|
||||
EncryptedPassword = encryptedPassword,
|
||||
SessionKey = sessionKey
|
||||
};
|
||||
|
||||
var loginResult = await IchniOnlineApiClient.Instance.PostAsync<LoginResponseDto>("/api/auth/login", loginDto);
|
||||
|
||||
IsLoggingIn = false;
|
||||
|
||||
if (loginResult.IsSuccess)
|
||||
{
|
||||
LoginCacheManager.SaveAuthSession(loginResult.Data.Token, loginResult.Data);
|
||||
IchniOnlineApiClient.Instance.JwtToken = loginResult.Data.Token;
|
||||
OnLoginSuccess?.Invoke(loginResult.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMessage = $"登录失败: {loginResult.Message}";
|
||||
if (!string.IsNullOrEmpty(loginResult.ErrorDetail))
|
||||
errorMessage += $" ({loginResult.ErrorDetail})";
|
||||
OnLoginFailed?.Invoke(errorMessage);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsLoggingIn = false;
|
||||
Debug.LogError($"[IchniOnlineAuthService] 密码登录异常: {ex}");
|
||||
OnLoginFailed?.Invoke($"登录异常: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Register
|
||||
|
||||
/// <summary>
|
||||
/// 用户注册流程:POST /api/auth/register
|
||||
/// 注册成功后触发 OnLoginSuccess(null)(注册不返回 JWT)
|
||||
/// </summary>
|
||||
public static async void Register(string username, string password, string displayName)
|
||||
{
|
||||
if (IsLoggingIn)
|
||||
{
|
||||
Debug.LogWarning("[IchniOnlineAuthService] 已有登录流程正在进行中");
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
|
||||
{
|
||||
OnLoginFailed?.Invoke("用户名或密码不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
IsLoggingIn = true;
|
||||
|
||||
try
|
||||
{
|
||||
var registerDto = new RegisterRequestDto
|
||||
{
|
||||
Username = username,
|
||||
Password = password,
|
||||
DisplayName = displayName
|
||||
};
|
||||
|
||||
var result = await IchniOnlineApiClient.Instance.PostAsync<object>("/api/auth/register", registerDto);
|
||||
|
||||
IsLoggingIn = false;
|
||||
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
OnLoginSuccess?.Invoke(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMessage = $"注册失败: {result.Message}";
|
||||
if (!string.IsNullOrEmpty(result.ErrorDetail))
|
||||
errorMessage += $" ({result.ErrorDetail})";
|
||||
OnLoginFailed?.Invoke(errorMessage);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsLoggingIn = false;
|
||||
Debug.LogError($"[IchniOnlineAuthService] 注册异常: {ex}");
|
||||
OnLoginFailed?.Invoke($"注册异常: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Logout
|
||||
|
||||
/// <summary>
|
||||
/// 登出流程:清除本地会话、登出 TapTap、清除 API JWT Token
|
||||
/// </summary>
|
||||
public static void Logout()
|
||||
{
|
||||
LoginCacheManager.ClearSession();
|
||||
ThirdPartyServiceManager.Instance?.Logout();
|
||||
IchniOnlineApiClient.Instance.JwtToken = null;
|
||||
Debug.Log("[IchniOnlineAuthService] 已登出");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Encryption
|
||||
|
||||
/// <summary>
|
||||
/// 使用 XOR 算法加密密码,与服务器 UserService.DecryptPassword 对应。
|
||||
/// sessionKey 为服务器返回的 Base64 字符串。
|
||||
/// </summary>
|
||||
public static string EncryptPassword(string password, string sessionKey)
|
||||
{
|
||||
if (string.IsNullOrEmpty(password))
|
||||
throw new ArgumentException("密码不能为空", nameof(password));
|
||||
if (string.IsNullOrEmpty(sessionKey))
|
||||
throw new ArgumentException("sessionKey 不能为空", nameof(sessionKey));
|
||||
|
||||
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
|
||||
byte[] sessionBytes = Convert.FromBase64String(sessionKey);
|
||||
byte[] encrypted = new byte[passwordBytes.Length];
|
||||
|
||||
for (int i = 0; i < passwordBytes.Length; i++)
|
||||
{
|
||||
encrypted[i] = (byte)(passwordBytes[i] ^ sessionBytes[i % sessionBytes.Length]);
|
||||
}
|
||||
|
||||
return Convert.ToBase64String(encrypted);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Online/Logic/AuthService.cs.meta
Normal file
2
Assets/Scripts/Online/Logic/AuthService.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd73d635812aee54e88f24a18de8fe4d
|
||||
8
Assets/Scripts/Online/Network.meta
Normal file
8
Assets/Scripts/Online/Network.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90618a8397b3df247aa0b6dff373aa35
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
122
Assets/Scripts/Online/Network/ApiClient.cs
Normal file
122
Assets/Scripts/Online/Network/ApiClient.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Best.HTTP;
|
||||
using IchniOnline.Online.Network.Models;
|
||||
using UnityEngine;
|
||||
|
||||
namespace IchniOnline.Online.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// BestHTTP-based API client singleton for IchniOnline backend communication.
|
||||
/// Pure HTTP layer — no business logic.
|
||||
/// </summary>
|
||||
public class IchniOnlineApiClient
|
||||
{
|
||||
private static IchniOnlineApiClient _instance;
|
||||
public static IchniOnlineApiClient Instance => _instance ??= new IchniOnlineApiClient();
|
||||
|
||||
public string BaseUrl { get; set; } = "http://localhost:5433";
|
||||
public string JwtToken { get; set; }
|
||||
|
||||
private IchniOnlineApiClient() { }
|
||||
|
||||
public async Task<ApiResult<T>> GetAsync<T>(string endpoint)
|
||||
{
|
||||
string url = BuildUrl(endpoint);
|
||||
var request = new HTTPRequest(new Uri(url), HTTPMethods.Get);
|
||||
AddAuthHeader(request);
|
||||
|
||||
try
|
||||
{
|
||||
var resp = await request.GetHTTPResponseAsync();
|
||||
return ProcessResponse<T>(resp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResult<T>.Fail(ResponseCode.InternalServerError, "Network error", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResult<T>> PostAsync<T>(string endpoint, object body)
|
||||
{
|
||||
string url = BuildUrl(endpoint);
|
||||
var request = new HTTPRequest(new Uri(url), HTTPMethods.Post);
|
||||
request.SetHeader("Content-Type", "application/json");
|
||||
AddAuthHeader(request);
|
||||
|
||||
if (body != null)
|
||||
{
|
||||
string jsonBody = JsonUtility.ToJson(body);
|
||||
request.UploadSettings.UploadStream = new MemoryStream(Encoding.UTF8.GetBytes(jsonBody));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var resp = await request.GetHTTPResponseAsync();
|
||||
return ProcessResponse<T>(resp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResult<T>.Fail(ResponseCode.InternalServerError, "Network error", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildUrl(string endpoint)
|
||||
{
|
||||
if (string.IsNullOrEmpty(BaseUrl))
|
||||
throw new InvalidOperationException("BaseUrl is not configured.");
|
||||
|
||||
string baseUrl = BaseUrl.TrimEnd('/');
|
||||
string path = endpoint.StartsWith("/") ? endpoint : $"/{endpoint}";
|
||||
return baseUrl + path;
|
||||
}
|
||||
|
||||
private void AddAuthHeader(HTTPRequest request)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(JwtToken))
|
||||
{
|
||||
request.SetHeader("Authorization", $"Bearer {JwtToken}");
|
||||
}
|
||||
}
|
||||
|
||||
private ApiResult<T> ProcessResponse<T>(HTTPResponse resp)
|
||||
{
|
||||
string json = resp.DataAsText;
|
||||
|
||||
if (resp.StatusCode >= 200 && resp.StatusCode < 300)
|
||||
{
|
||||
if (string.IsNullOrEmpty(json))
|
||||
{
|
||||
return ApiResult<T>.Fail(ResponseCode.InternalServerError, "Empty response body");
|
||||
}
|
||||
|
||||
var response = JsonUtility.FromJson(json, typeof(GlobalResponse<T>)) as GlobalResponse<T>;
|
||||
if (response == null)
|
||||
{
|
||||
return ApiResult<T>.Fail(ResponseCode.InternalServerError, "Failed to parse response JSON");
|
||||
}
|
||||
|
||||
if (response.Code == ResponseCode.Ok)
|
||||
{
|
||||
return ApiResult<T>.Ok(response.Data);
|
||||
}
|
||||
|
||||
return ApiResult<T>.Fail(response.Code, response.Message);
|
||||
}
|
||||
|
||||
// Non-2xx: try to parse server error body
|
||||
if (!string.IsNullOrEmpty(json))
|
||||
{
|
||||
var errorResponse = JsonUtility.FromJson(json, typeof(GlobalResponseBase)) as GlobalResponseBase;
|
||||
if (errorResponse != null)
|
||||
{
|
||||
return ApiResult<T>.Fail(errorResponse.Code, errorResponse.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return ApiResult<T>.Fail(ResponseCode.InternalServerError, $"HTTP error {resp.StatusCode}");
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Online/Network/ApiClient.cs.meta
Normal file
2
Assets/Scripts/Online/Network/ApiClient.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df4f4d9b75196d348b949150b5acc91b
|
||||
8
Assets/Scripts/Online/Network/Models.meta
Normal file
8
Assets/Scripts/Online/Network/Models.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 78f43963c5d92354da175c3f74339cac
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
82
Assets/Scripts/Online/Network/Models/ApiResponse.cs
Normal file
82
Assets/Scripts/Online/Network/Models/ApiResponse.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
namespace IchniOnline.Online.Network.Models
|
||||
{
|
||||
using System;
|
||||
|
||||
[System.Serializable]
|
||||
public enum ResponseCode
|
||||
{
|
||||
Ok = 10000,
|
||||
BadRequest = 10400,
|
||||
Unauthorized = 10401,
|
||||
Forbidden = 10403,
|
||||
NotFound = 10404,
|
||||
InternalServerError = 10500
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Non-generic base class for Unity JsonUtility deserialization.
|
||||
/// Concrete generic GlobalResponse<T> inherits from this.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public abstract class GlobalResponseBase
|
||||
{
|
||||
public ResponseCode Code;
|
||||
public string Message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic server response wrapper. JsonUtility can deserialize this to the base class,
|
||||
/// then cast to the concrete type for Data access.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Data payload type</typeparam>
|
||||
[System.Serializable]
|
||||
public class GlobalResponse<T> : GlobalResponseBase
|
||||
{
|
||||
public T Data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unified API result wrapper with factory methods.
|
||||
/// Note: JsonUtility doesn't support generic deserialization directly,
|
||||
/// so use GlobalResponseBase for deserialization then wrap in ApiResult.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Data payload type</typeparam>
|
||||
[System.Serializable]
|
||||
public class ApiResult<T>
|
||||
{
|
||||
public bool IsSuccess => Code == ResponseCode.Ok;
|
||||
public T Data { get; private set; }
|
||||
public ResponseCode Code { get; private set; }
|
||||
public string Message { get; private set; }
|
||||
public string ErrorDetail { get; private set; }
|
||||
|
||||
private ApiResult() { }
|
||||
|
||||
public static ApiResult<T> Ok(T data)
|
||||
{
|
||||
return new ApiResult<T>
|
||||
{
|
||||
Data = data,
|
||||
Code = ResponseCode.Ok,
|
||||
Message = "Success",
|
||||
ErrorDetail = null
|
||||
};
|
||||
}
|
||||
|
||||
public static ApiResult<T> Fail(ResponseCode code, string message, string detail = null)
|
||||
{
|
||||
return new ApiResult<T>
|
||||
{
|
||||
Data = default(T),
|
||||
Code = code,
|
||||
Message = message,
|
||||
ErrorDetail = detail
|
||||
};
|
||||
}
|
||||
|
||||
public static ApiResult<T> Fail(int code, string message, string detail = null)
|
||||
{
|
||||
return Fail((ResponseCode)code, message, detail);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Online/Network/Models/ApiResponse.cs.meta
Normal file
2
Assets/Scripts/Online/Network/Models/ApiResponse.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 476434455b6d65a4494c003a2ae54754
|
||||
46
Assets/Scripts/Online/Network/Models/AuthDtos.cs
Normal file
46
Assets/Scripts/Online/Network/Models/AuthDtos.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace IchniOnline.Online.Network.Models
|
||||
{
|
||||
[Serializable]
|
||||
public class ThirdPartyLoginRequestDto
|
||||
{
|
||||
public string Token;
|
||||
public string TokenType;
|
||||
public string MacKey;
|
||||
public string MacAlgorithm;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LoginRequestDto
|
||||
{
|
||||
public string Username;
|
||||
public string EncryptedPassword;
|
||||
public string SessionKey;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RegisterRequestDto
|
||||
{
|
||||
public string Username;
|
||||
public string Password;
|
||||
public string DisplayName;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LoginResponseDto
|
||||
{
|
||||
public string Token;
|
||||
public UserResponseDto User;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class UserResponseDto
|
||||
{
|
||||
public string UserId;
|
||||
public string Username;
|
||||
public string DisplayName;
|
||||
public string AvatarUrl;
|
||||
public int Permission;
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Online/Network/Models/AuthDtos.cs.meta
Normal file
2
Assets/Scripts/Online/Network/Models/AuthDtos.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d4424c69a64b3a43a48a432b2626ac9
|
||||
3
Assets/Scripts/Online/Resources.meta
Normal file
3
Assets/Scripts/Online/Resources.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 907170849dc345b29c0f7d072e1ca5db
|
||||
timeCreated: 1781501503
|
||||
Reference in New Issue
Block a user