♻️ Updated auth challenges and device API to fit new design

This commit is contained in:
2025-12-03 22:43:35 +08:00
parent 4faa1a4b64
commit 4a71f92ef0
3 changed files with 52 additions and 23 deletions

View File

@@ -560,7 +560,7 @@ public class AccountCurrentController(
[HttpGet("devices")]
[Authorize]
public async Task<ActionResult<List<SnAuthClientWithChallenge>>> GetDevices()
public async Task<ActionResult<List<SnAuthClientWithSessions>>> GetDevices()
{
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser ||
HttpContext.Items["CurrentSession"] is not SnAuthSession currentSession) return Unauthorized();
@@ -571,18 +571,41 @@ public class AccountCurrentController(
.Where(device => device.AccountId == currentUser.Id)
.ToListAsync();
var challengeDevices = devices.Select(SnAuthClientWithChallenge.FromClient).ToList();
var deviceIds = challengeDevices.Select(x => x.DeviceId).ToList();
var sessionDevices = devices.Select(SnAuthClientWithSessions.FromClient).ToList();
var clientIds = sessionDevices.Select(x => x.Id).ToList();
var authChallenges = await db.AuthChallenges
.Where(c => deviceIds.Contains(c.DeviceId))
.GroupBy(c => c.DeviceId)
var authSessions = await db.AuthSessions
.Where(c => clientIds.Contains(c.Id))
.GroupBy(c => c.Id)
.ToDictionaryAsync(c => c.Key, c => c.ToList());
foreach (var challengeDevice in challengeDevices)
if (authChallenges.TryGetValue(challengeDevice.DeviceId, out var challenge))
challengeDevice.Challenges = challenge;
foreach (var dev in sessionDevices)
if (authSessions.TryGetValue(dev.Id, out var challenge))
dev.Sessions = challenge;
return Ok(challengeDevices);
return Ok(sessionDevices);
}
[HttpGet("challenges")]
[Authorize]
public async Task<ActionResult<List<SnAuthChallenge>>> GetChallenges(
[FromQuery] int take = 20,
[FromQuery] int offset = 0
)
{
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var query = db.AuthChallenges
.Where(challenge => challenge.AccountId == currentUser.Id)
.OrderByDescending(c => c.CreatedAt);
var total = await query.CountAsync();
Response.Headers.Append("X-Total", total.ToString());
var challenges = await query
.Skip(offset)
.Take(take)
.ToListAsync();
return Ok(challenges);
}
[HttpGet("sessions")]
@@ -596,6 +619,7 @@ public class AccountCurrentController(
HttpContext.Items["CurrentSession"] is not SnAuthSession currentSession) return Unauthorized();
var query = db.AuthSessions
.OrderByDescending(x => x.LastGrantedAt)
.Include(session => session.Account)
.Where(session => session.Account.Id == currentUser.Id);
@@ -604,7 +628,6 @@ public class AccountCurrentController(
Response.Headers.Append("X-Auth-Session", currentSession.Id.ToString());
var sessions = await query
.OrderByDescending(x => x.LastGrantedAt)
.Skip(offset)
.Take(take)
.ToListAsync();

View File

@@ -48,7 +48,8 @@ public class AuthService(
.Take(10)
.ToListAsync();
var recentChallengeIds = recentSessions.Where(s => s.ChallengeId != null).Select(s => s.ChallengeId.Value).ToList();
var recentChallengeIds =
recentSessions.Where(s => s.ChallengeId != null).Select(s => s.ChallengeId.Value).ToList();
var recentChallenges = await db.AuthChallenges.Where(c => recentChallengeIds.Contains(c.Id)).ToListAsync();
var ipAddress = request.HttpContext.Connection.RemoteIpAddress?.ToString();
@@ -192,7 +193,7 @@ public class AuthService(
CreatedAt = time,
LastGrantedAt = time,
IpAddress = HttpContext.Connection.RemoteIpAddress?.ToString(),
UserAgent = HttpContext.Request.Headers.UserAgent,
UserAgent = HttpContext.Request.Headers.UserAgent,
AppId = customAppId,
ParentSessionId = parentSession?.Id,
Type = customAppId is not null ? SessionType.OAuth : SessionType.Oidc,
@@ -409,8 +410,12 @@ public class AuthService(
if (challenge.StepRemain != 0)
throw new ArgumentException("Challenge not yet completed.");
var device = await GetOrCreateDeviceAsync(challenge.AccountId, challenge.DeviceId, challenge.DeviceName,
challenge.Platform);
var device = await GetOrCreateDeviceAsync(
challenge.AccountId,
challenge.DeviceId,
challenge.DeviceName,
challenge.Platform
);
var now = SystemClock.Instance.GetCurrentInstant();
var session = new SnAuthSession
@@ -421,7 +426,7 @@ public class AuthService(
IpAddress = challenge.IpAddress,
UserAgent = challenge.UserAgent,
Scopes = challenge.Scopes,
Audiences = challenge.Audiences,
Audiences = challenge.Audiences,
ChallengeId = challenge.Id,
ClientId = device.Id,
};
@@ -537,7 +542,8 @@ public class AuthService(
return key;
}
public async Task<SnApiKey> CreateApiKey(Guid accountId, string label, Instant? expiredAt = null, SnAuthSession? parentSession = null)
public async Task<SnApiKey> CreateApiKey(Guid accountId, string label, Instant? expiredAt = null,
SnAuthSession? parentSession = null)
{
var key = new SnApiKey
{

View File

@@ -153,13 +153,13 @@ public class SnAuthClient : ModelBase
};
}
public class SnAuthClientWithChallenge : SnAuthClient
public class SnAuthClientWithSessions : SnAuthClient
{
public List<SnAuthChallenge> Challenges { get; set; } = [];
public List<SnAuthSession> Sessions { get; set; } = [];
public static SnAuthClientWithChallenge FromClient(SnAuthClient client)
public static SnAuthClientWithSessions FromClient(SnAuthClient client)
{
return new SnAuthClientWithChallenge
return new SnAuthClientWithSessions
{
Id = client.Id,
Platform = client.Platform,