Files
caliverse_server/BrokerApiCore/Services/UserAuthService.cs
2025-05-01 07:23:28 +09:00

204 lines
6.1 KiB
C#

using System.IdentityModel.Tokens.Jwt;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
namespace BrokerApiCore;
public class UserAuthService
{
private readonly PlanetUserEntity m_planet_user_entity;
private readonly SsoAccountRepo m_sso_account_repo;
private readonly IServerLogic m_server_logic;
public string AccountId
=> m_planet_user_entity.getEntityAttributeNotNull<AccountAttribute>().AccountId;
// public string Email { get; set; } = string.Empty;
public string UserGuid
=> m_planet_user_entity.getEntityAttributeNotNull<AccountAttribute>().UserGuid;
public string Nickname
=> m_planet_user_entity.getEntityAttributeNotNull<NicknameAttribute>().Nickname;
public IServerLogic ServerLogic => m_server_logic;
public PlanetUserEntity PlanetUserEntity => m_planet_user_entity;
private ServerConfigMetaverseBroker? getServerConfig()
{
return m_server_logic.getServerConfig() as ServerConfigMetaverseBroker;
}
public UserAuthService(SsoAccountRepo ssoAccountRepo, IServerLogic serverLogic)
{
m_sso_account_repo = ssoAccountRepo;
m_server_logic = serverLogic;
m_planet_user_entity = new PlanetUserEntity(serverLogic);
m_planet_user_entity.onInit().Wait();
}
public async Task<Result> authByWebPortalToken(string webPortalToken, string? planetId = null)
{
if (planetId is not null)
{
m_planet_user_entity.setPlanetId(planetId);
}
var m_sso_jwt_secret_key = getServerConfig()?.SsoAccountAuthJwtSecretKey ?? string.Empty;
Guard.Against.isNullOrEmptyOrWhiteSpace(m_sso_jwt_secret_key, ServerErrorCode.InternalServerError,
()=>"SSO JWT secret key is required in server config");
var jwt_result = verifySsoAccountAuthJwt(webPortalToken,
m_sso_jwt_secret_key,
out var account_id, out var account_type, out var access_token);
if (jwt_result.isFail())
{
var error_msg = $"Broker Api Failed to Auth From Jwt !!! : {jwt_result.toBasicString()}, {webPortalToken}";
Log.getLogger().error(error_msg);
return jwt_result;
}
var result = await authByAccount(account_id);
if (result.isSuccess())
{
if (planetId is not null)
{
// BrokerBusinessLogger.collectLog(m_planet_user_entity, LogActionType.BrokerApiUserLogin, new UserAuthLogInfo
// {
// AccountId = account_id,
// UserGuid = UserGuid,
// Nickname = Nickname,
// });
BusinessLogger.collectLog(m_planet_user_entity,
new PlanetUserAuthBusinessLog(
new PlanetUserAuthLogData { AccountId = account_id, UserGuid = UserGuid, Nickname = Nickname, },
LogActionType.BrokerApiUserLogin));
}
}
return result;
}
public async Task<Result> authFromEmail(string email)
{
var (result, sso_account) = await m_sso_account_repo.findOneByEmail(email);
Guard.Against.resultFail(result);
Guard.Against.isNull(sso_account, ServerErrorCode.AccountNotFound, ()=>"sso account not found");
result = await authByAccount(sso_account.Id.ToString());
Guard.Against.resultFail(result);
Guard.Against.isNull(sso_account, ServerErrorCode.UserNotFound, ()=>"user not found");
return result;
}
// todo: JwtParser를 사용해서 수정할 것
private Result verifySsoAccountAuthJwt(string ssoJwt
, string ssoJwtSecret
, out string id, out AccountType accountType, out UInt64 accessToken)
{
id = string.Empty;
accountType = AccountType.None;
accessToken = 0;
var result = new Result();
var err_msg = string.Empty;
try
{
var token_handler = new JwtSecurityTokenHandler();
var validation_parameters = getValidationUserTokenParameters(ssoJwtSecret);
var claim = token_handler.ValidateToken(ssoJwt, validation_parameters, out var validated_token);
// account id
id = claim.Claims.FirstOrDefault(x => x.Type == "id")?.Value ?? string.Empty;
// account type
accountType = claim.Claims.FirstOrDefault(x => x.Type == "accountType")?.Value
?.convertEnumTypeAndValueStringToEnum(AccountType.None) ?? AccountType.None;
// access token
var access_token_string = claim.Claims.FirstOrDefault(x => x.Type == "accessToken")?.Value;
accessToken = Convert.ToUInt64(access_token_string);
}
catch (SecurityTokenExpiredException e)
{
err_msg = $"Expired WebAuthJWT !!! : SecurityTokenExpiredException:{e}";
result.setFail(ServerErrorCode.ExpiredUserJwt, err_msg);
}
catch (SecurityTokenException e)
{
err_msg = $"Failed to verify WebAuthJWT !!! : SecurityTokenException:{e}";
result.setFail(ServerErrorCode.InvalidUserJwt, err_msg);
}
catch (Exception e)
{
err_msg = $"Exception !!!, WebAuthJWT !!! : Exception:{e}";
result.setFail(ServerErrorCode.InvalidUserJwt, err_msg);
}
if (result.isFail())
{
result = verifyForTestUserToken(ssoJwt, ssoJwtSecret, out id, out accountType, out accessToken);
}
Guard.Against.resultFail(result);
return result;
}
// 치트를 허용하도록 처리함
private Result verifyForTestUserToken(string ssoJwt
, string ssoJwtSecret
, out string id, out AccountType accountType, out UInt64 accessToken)
{
var splits = ssoJwt.Split('|');
if (splits.Length < 1 || splits[1] != ssoJwtSecret)
{
id = string.Empty;
accountType = AccountType.None;
accessToken = 0;
return new Result
{
ErrorCode = ServerErrorCode.InvalidUserJwt, ResultString = "Failed to verify WebAuthJWT"
};
}
id = splits[0];
accountType = AccountType.None;
try
{
accessToken = Convert.ToUInt64(id);
}
catch (Exception e)
{
accessToken = 0;
}
return new Result();
}
private static TokenValidationParameters getValidationUserTokenParameters(string sdsoAccountAuthJwtSecretKey)
{
return new TokenValidationParameters()
{
ValidateLifetime = true,
ValidateAudience = false,
ValidateIssuer = false,
ValidIssuer = "",
ValidAudience = "",
IssuerSigningKey =
new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(
sdsoAccountAuthJwtSecretKey))
};
}
public async Task<Result> authByAccount(string accountId)
{
var action = m_planet_user_entity.getEntityActionNotNull<UserAuthAction>();
return await action.findAndSetAllAttributeByAccountId(accountId);
}
}