Added distributed caching for access and refresh tokens in both `AuthController` and `AppProxyController`. Introduced logic to handle token expiration and refresh, ensuring continuous authorization through token renewal and session management.
116 lines
3.6 KiB
C#
116 lines
3.6 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Extensions.Caching.Distributed;
|
|
using Suspectus.Gandalf.Core.Abstractions.CQRS.Commands;
|
|
using Suspectus.Gandalf.Core.Abstractions.DTOs.Internal.Auth;
|
|
using Suspectus.Gandalf.Core.Abstractions.Extensions;
|
|
using Suspectus.Gandalf.Palantir.Client;
|
|
|
|
namespace Suspectus.Gandalf.Bridgekeeper.Api.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/[controller]")]
|
|
public class AuthController : ControllerBase
|
|
{
|
|
private readonly IPalantirClient _client;
|
|
private readonly IDistributedCache _tokenCache;
|
|
|
|
public AuthController(IPalantirClient client, IDistributedCache tokenCache)
|
|
{
|
|
_client = client;
|
|
_tokenCache = tokenCache;
|
|
}
|
|
|
|
[HttpGet("[action]")]
|
|
public async Task<IActionResult> Check()
|
|
{
|
|
return Ok(true);
|
|
}
|
|
|
|
[HttpPost("[action]")]
|
|
public async Task<IActionResult> Login([FromBody] ValidateCredentialsCommand validateCredentialsCommand, [FromQuery] string? clientId, CancellationToken cancellationToken)
|
|
{
|
|
if (clientId is null)
|
|
{
|
|
var masterAppInfoResponse = await _client.Internal.App.GetMasterInfo();
|
|
|
|
if (masterAppInfoResponse.IsFaulted)
|
|
{
|
|
return BadRequest($"Failed to retrieve master app info.");
|
|
}
|
|
|
|
clientId = masterAppInfoResponse.GetValue().Id;
|
|
}
|
|
|
|
var tokenRequestCommandResponse = await _client.Internal.Auth.Token(new TokenRequestCommand
|
|
{
|
|
Password = validateCredentialsCommand.Password,
|
|
Username = validateCredentialsCommand.UsernameOrEmail,
|
|
GrandType = GrandType.Password,
|
|
ClientId = clientId
|
|
});
|
|
|
|
if (tokenRequestCommandResponse.IsFaulted)
|
|
{
|
|
return tokenRequestCommandResponse.Match<IActionResult>(
|
|
BadRequest,
|
|
e => BadRequest($"{e.Message}\n{e.InnerException?.Message}")
|
|
);
|
|
}
|
|
|
|
var tokenRequestResponse = tokenRequestCommandResponse.GetValue();
|
|
|
|
if (tokenRequestResponse is null)
|
|
{
|
|
return BadRequest("Invalid username or password.");
|
|
}
|
|
|
|
await _tokenCache.SetStringAsync(
|
|
GetCacheKey(tokenRequestResponse.SubjectId, clientId, "access_token"),
|
|
tokenRequestResponse.AccessToken,
|
|
new DistributedCacheEntryOptions
|
|
{
|
|
AbsoluteExpiration = tokenRequestResponse.AccessTokenExpiresAt.AddSeconds(-10),
|
|
},
|
|
cancellationToken
|
|
);
|
|
|
|
await _tokenCache.SetStringAsync(
|
|
GetCacheKey(tokenRequestResponse.SubjectId, clientId, "refresh_token"),
|
|
tokenRequestResponse.RefreshToken,
|
|
new DistributedCacheEntryOptions
|
|
{
|
|
AbsoluteExpiration = tokenRequestResponse.RefreshTokenExpiresAt.AddSeconds(-10),
|
|
},
|
|
cancellationToken
|
|
);
|
|
|
|
Response.Cookies.Append("MithrandirSession", tokenRequestResponse.SubjectId, new CookieOptions
|
|
{
|
|
Secure = true,
|
|
HttpOnly = true,
|
|
SameSite = SameSiteMode.Lax,
|
|
Expires = tokenRequestResponse.RefreshTokenExpiresAt.AddSeconds(-10)
|
|
});
|
|
|
|
return Ok();
|
|
}
|
|
|
|
[HttpGet("[action]")]
|
|
public async Task<IActionResult> Logout()
|
|
{
|
|
Response.Cookies.Delete("MithrandirSession");
|
|
|
|
return Ok();
|
|
}
|
|
|
|
[HttpPost("[action]")]
|
|
public async Task<IActionResult> Register()
|
|
{
|
|
return Ok(true);
|
|
}
|
|
|
|
private string GetCacheKey(string subjectId, string appId, string tokenType)
|
|
{
|
|
return $"{subjectId}:{appId}:{tokenType}";
|
|
}
|
|
} |