Files
Campus-25/server/Server/2025-RecRoom-Server-E12354-main/Controllers/PhotonAuthController.cs
T
2026-10-14 06:59:51 +02:00

88 lines
4.1 KiB
C#

using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Campus_live_rewrite.api.server;
using Campus_live_rewrite.api.server.Classes.db_class;
namespace Campus_live_rewrite.Controllers
{
// Photon Cloud "Custom Authentication" webhook.
//
// In the Photon dashboard for each app (Realtime / Voice / Chat), set:
// Authentication -> Custom Server -> Custom -> AuthUrl:
// https://gameauth.ddns.net/photon/auth
//
// Photon will call this endpoint on every client connect, passing whatever token the client
// presented in AuthValues (the client hands out photon_access_token via RoomController's
// /Room_server/photon_access_token endpoint - see Createphotonacesstoken in ClientSecurity).
// We validate it as our own JWT, and echo back the real account id as the Photon UserId -
// which the client CANNOT forge at the Photon protocol level (matches the pattern the 2023
// Campus-Server used, see PhotonAuthController.cs there).
//
// Contract: reply 200 with JSON { ResultCode, UserId, Nickname }.
// ResultCode 1 = authenticated, 2 = failed / unauthorized, 3 = required params missing.
// If custom auth isn't configured on the Photon apps this endpoint just never gets called -
// it costs nothing to ship, and makes the server ready the moment custom auth is turned on.
[ApiController]
public class PhotonAuthController : ControllerBase
{
[HttpGet("/photon/auth")]
[HttpPost("/photon/auth")]
public async Task<IActionResult> Authenticate([FromQuery] string? token)
{
// The token can arrive as a query param (AuthGetParameters), form/body (AuthPostData),
// or as the raw body - accept all shapes so either GET or POST configuration works.
string? t = token;
if (string.IsNullOrEmpty(t))
foreach (var k in new[] { "token", "access_token", "t", "sig", "authToken" })
if (Request.Query.TryGetValue(k, out var q) && !string.IsNullOrEmpty(q)) { t = q; break; }
if (string.IsNullOrEmpty(t) && Request.HasFormContentType)
foreach (var k in new[] { "token", "access_token", "t", "authToken" })
if (Request.Form.TryGetValue(k, out var f) && !string.IsNullOrEmpty(f)) { t = f; break; }
if (string.IsNullOrEmpty(t))
{
try
{
using var r = new StreamReader(Request.Body);
var body = (await r.ReadToEndAsync()).Trim().Trim('"');
if (!string.IsNullOrWhiteSpace(body) && body.Count(c => c == '.') == 2) t = body;
}
catch { }
}
if (string.IsNullOrEmpty(t))
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss} [photon-auth] no token in request ({Request.QueryString}) -> ResultCode 3");
return Ok(new { ResultCode = 3, Message = "missing token" });
}
string decoded = ClientSecurity.DecodeToken(t);
if (string.IsNullOrEmpty(decoded) || decoded.StartsWith("error_"))
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss} [photon-auth] token failed validation ({decoded}) -> ResultCode 2");
return Ok(new { ResultCode = 2, Message = "invalid token" });
}
player_info? account = null;
try { account = JsonConvert.DeserializeObject<player_info>(decoded); } catch { }
if (account == null)
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss} [photon-auth] token decoded but no player_info -> ResultCode 2");
return Ok(new { ResultCode = 2, Message = "no account" });
}
string nickname = account.Username ?? account.Id.ToString();
Console.WriteLine($"{DateTime.Now:HH:mm:ss} [photon-auth] authenticated @{nickname} as UserId {account.Id}");
return Ok(new
{
ResultCode = 1,
UserId = account.Id.ToString(),
Nickname = nickname
});
}
}
}