Files
CC-Framework.BriskGameServer/PackageSource/com.foldcc.cc-framework.brisk-game-server/Runtime/Auth/BriskAuthModule.cs

148 lines
4.7 KiB
C#
Raw Normal View History

2026-04-10 22:06:39 +08:00
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
/// <summary>
/// Brisk 认证模块。
/// </summary>
2026-04-10 22:06:39 +08:00
public sealed class BriskAuthModule
: BriskModuleBase
{
/// <summary>
/// 通过稳定的第三方用户 ID 换取 Brisk 登录态。
/// </summary>
2026-04-10 22:06:39 +08:00
public async Task<BriskLoginResult> LoginWithUserIdAsync(string loginProvider, string loginUserId, BriskProfile profile = null)
{
RequireNotEmpty(loginProvider, nameof(loginProvider));
RequireNotEmpty(loginUserId, nameof(loginUserId));
return await LoginInternalAsync(CreateLoginBody(loginProvider, profile, loginUserId, null), loginProvider, loginUserId);
}
/// <summary>
/// 通过第三方返回的 code 换取 Brisk 登录态。
/// </summary>
2026-04-10 22:06:39 +08:00
public async Task<BriskLoginResult> LoginWithCodeAsync(string loginProvider, string code, BriskProfile profile = null)
{
RequireNotEmpty(loginProvider, nameof(loginProvider));
RequireNotEmpty(code, nameof(code));
return await LoginInternalAsync(CreateLoginBody(loginProvider, profile, null, code), loginProvider, null);
}
/// <summary>
/// 登出当前账号并清理本地会话。
/// </summary>
2026-04-10 22:06:39 +08:00
public async Task LogoutAsync()
{
var context = GetContext();
try
{
if (context.Session.HasAccessToken)
{
await context.HttpClient.PostJsonAsync("/auth/logout", new Dictionary<string, object>(), true);
}
}
catch (BriskAuthExpiredException)
{
// Local logout should still succeed even if the remote token has already expired.
}
catch (BriskBlockingException exception)
{
Brisk.NotifyBlockingError(exception);
throw;
}
finally
{
context.Session.Clear();
await context.TokenStore.ClearAsync();
Brisk.NotifyLoggedOut();
}
}
private async Task<BriskLoginResult> LoginInternalAsync(Dictionary<string, object> body, string requestedLoginProvider, string requestedLoginUserId)
{
return await ExecutePublicAsync(async context =>
{
var data = await context.HttpClient.PostJsonAsync("/auth/login/exchange", body, false);
var result = BriskModelMapper.ToLoginResult(data);
if (string.IsNullOrWhiteSpace(result.LoginProvider))
{
result.LoginProvider = requestedLoginProvider;
}
if (string.IsNullOrWhiteSpace(result.LoginUserId))
{
result.LoginUserId = requestedLoginUserId;
}
await UpdateSessionAsync(context, result);
Brisk.NotifyLoggedIn();
return result;
});
}
private Dictionary<string, object> CreateLoginBody(string loginProvider, BriskProfile profile, string loginUserId, string code)
{
var context = GetContext();
var body = new Dictionary<string, object>
{
{ "game_key", context.Options.GameKey },
{ "login_provider", loginProvider }
};
AddIfNotEmpty(body, "login_user_id", loginUserId);
AddIfNotEmpty(body, "code", code);
AddIfNotEmpty(body, "device_id", context.Options.DeviceId);
AddIfNotEmpty(body, "client_version", context.Options.ClientVersion);
if (profile != null)
{
AddIfNotEmpty(body, "nickname", profile.Nickname);
AddIfNotEmpty(body, "avatar_url", profile.AvatarUrl);
if (profile.ProfileJson != null)
{
body["profile_json"] = profile.ProfileJson;
}
}
return body;
}
private static void AddIfNotEmpty(Dictionary<string, object> body, string key, string value)
{
if (!string.IsNullOrWhiteSpace(value))
{
body[key] = value;
}
}
private async Task UpdateSessionAsync(BriskContext context, BriskLoginResult result)
{
var expiresAt = result.ExpiresIn > 0
? DateTimeOffset.UtcNow.AddSeconds(result.ExpiresIn)
: (DateTimeOffset?)null;
context.Session.Update(
result.AccessToken,
expiresAt,
result.PlayerId,
result.ProjectAccountId,
result.LoginProvider,
result.LoginUserId);
var storedSession = new BriskStoredSession
{
AccessToken = result.AccessToken,
ExpiresAt = expiresAt,
PlayerId = result.PlayerId,
ProjectAccountId = result.ProjectAccountId,
LoginProvider = result.LoginProvider,
LoginUserId = result.LoginUserId
};
await context.TokenStore.SaveAsync(storedSession);
}
}