✨ Login with Apple
This commit is contained in:
@ -1,5 +1,8 @@
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Sphere.Auth.OpenId;
|
||||
|
||||
@ -8,7 +11,7 @@ namespace DysonNetwork.Sphere.Auth.OpenId;
|
||||
public class OidcController(
|
||||
IServiceProvider serviceProvider,
|
||||
AppDatabase db,
|
||||
Account.AccountService accountService,
|
||||
AccountService accounts,
|
||||
AuthService authService
|
||||
)
|
||||
: ControllerBase
|
||||
@ -35,6 +38,51 @@ public class OidcController(
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mobile Apple Sign In endpoint
|
||||
/// Handles Apple authentication directly from mobile apps
|
||||
/// </summary>
|
||||
[HttpPost("apple/mobile")]
|
||||
public async Task<ActionResult<AuthController.TokenExchangeResponse>> AppleMobileSignIn([FromBody] AppleMobileSignInRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get Apple OIDC service
|
||||
if (GetOidcService("apple") is not AppleOidcService appleService)
|
||||
return StatusCode(503, "Apple OIDC service not available");
|
||||
|
||||
// Prepare callback data for processing
|
||||
var callbackData = new OidcCallbackData
|
||||
{
|
||||
IdToken = request.IdentityToken,
|
||||
Code = request.AuthorizationCode,
|
||||
};
|
||||
|
||||
// Process the authentication
|
||||
var userInfo = await appleService.ProcessCallbackAsync(callbackData);
|
||||
|
||||
// Find or create user account using existing logic
|
||||
var account = await FindOrCreateAccount(userInfo, "apple");
|
||||
|
||||
// Create session using the OIDC service
|
||||
var session = await appleService.CreateSessionForUserAsync(userInfo, account);
|
||||
|
||||
// Generate token using existing auth service
|
||||
var token = authService.CreateToken(session);
|
||||
|
||||
return Ok(new AuthController.TokenExchangeResponse { Token = token });
|
||||
}
|
||||
catch (SecurityTokenValidationException ex)
|
||||
{
|
||||
return Unauthorized($"Invalid identity token: {ex.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log the error
|
||||
return StatusCode(500, $"Authentication failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private OidcService GetOidcService(string provider)
|
||||
{
|
||||
return provider.ToLower() switch
|
||||
@ -45,4 +93,51 @@ public class OidcController(
|
||||
_ => throw new ArgumentException($"Unsupported provider: {provider}")
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<Account.Account> FindOrCreateAccount(OidcUserInfo userInfo, string provider)
|
||||
{
|
||||
if (string.IsNullOrEmpty(userInfo.Email))
|
||||
throw new ArgumentException("Email is required for account creation");
|
||||
|
||||
// Check if account exists by email
|
||||
var existingAccount = await accounts.LookupAccount(userInfo.Email);
|
||||
if (existingAccount != null)
|
||||
{
|
||||
// Check if this provider connection already exists
|
||||
var existingConnection = await db.AccountConnections
|
||||
.FirstOrDefaultAsync(c => c.AccountId == existingAccount.Id &&
|
||||
c.Provider == provider &&
|
||||
c.ProvidedIdentifier == userInfo.UserId);
|
||||
|
||||
// If no connection exists, create one
|
||||
if (existingConnection != null) return existingAccount;
|
||||
var connection = new AccountConnection
|
||||
{
|
||||
AccountId = existingAccount.Id,
|
||||
Provider = provider,
|
||||
ProvidedIdentifier = userInfo.UserId!,
|
||||
};
|
||||
|
||||
db.AccountConnections.Add(connection);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return existingAccount;
|
||||
}
|
||||
|
||||
// Create new account using the AccountService
|
||||
var newAccount = await accounts.CreateAccount(userInfo);
|
||||
|
||||
// Create the provider connection
|
||||
var newConnection = new AccountConnection
|
||||
{
|
||||
AccountId = newAccount.Id,
|
||||
Provider = provider,
|
||||
ProvidedIdentifier = userInfo.UserId!,
|
||||
};
|
||||
|
||||
db.AccountConnections.Add(newConnection);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return newAccount;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user