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().AccountId; // public string Email { get; set; } = string.Empty; public string UserGuid => m_planet_user_entity.getEntityAttributeNotNull().UserGuid; public string Nickname => m_planet_user_entity.getEntityAttributeNotNull().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 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 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 authByAccount(string accountId) { var action = m_planet_user_entity.getEntityActionNotNull(); return await action.findAndSetAllAttributeByAccountId(accountId); } }