Authentication layer with user profile #4
7 changed files with 168 additions and 11 deletions
|
@ -1,4 +1,4 @@
|
||||||
// <copyright file="OAuthController.cs" company="alveus.dev">
|
// <copyright file="OAuthApiController.cs" company="alveus.dev">
|
||||||
// Copyright (c) alveus.dev. All rights reserved. Licensed under the MIT License.
|
// Copyright (c) alveus.dev. All rights reserved. Licensed under the MIT License.
|
||||||
// </copyright>
|
// </copyright>
|
||||||
|
|
||||||
|
@ -16,15 +16,15 @@ namespace Astral.ApiServer.Controllers;
|
||||||
/// OAuth authentication controller.
|
/// OAuth authentication controller.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("oauth")]
|
[Route("oauth")]
|
||||||
public class OAuthController : BaseApiController
|
public class OAuthApiController : BaseApiController
|
||||||
{
|
{
|
||||||
private readonly IAuthenticationService _authenticationService;
|
private readonly IAuthenticationService _authenticationService;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="OAuthController"/> class.
|
/// Initializes a new instance of the <see cref="OAuthApiController"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="authenticationService">Instance of <see cref="IAuthenticationService"/>.</param>
|
/// <param name="authenticationService">Instance of <see cref="IAuthenticationService"/>.</param>
|
||||||
public OAuthController(IAuthenticationService authenticationService)
|
public OAuthApiController(IAuthenticationService authenticationService)
|
||||||
{
|
{
|
||||||
_authenticationService = authenticationService;
|
_authenticationService = authenticationService;
|
||||||
}
|
}
|
67
Astral.ApiServer/Controllers/V1/UserApiController.cs
Normal file
67
Astral.ApiServer/Controllers/V1/UserApiController.cs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
// <copyright file="UserApiController.cs" company="alveus.dev">
|
||||||
|
// Copyright (c) alveus.dev. All rights reserved. Licensed under the MIT License.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
using Astral.ApiServer.Models;
|
||||||
|
using Astral.Services.Interfaces;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Astral.ApiServer.Controllers.V1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// User api controller.
|
||||||
|
/// </summary>
|
||||||
|
[Route("api/v1/user")]
|
||||||
|
[Authorize]
|
||||||
|
public class UserApiController : BaseApiController
|
||||||
|
{
|
||||||
|
private readonly IIdentityProvider _identityProvider;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UserApiController"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="identityProvider">Instance of <see cref="IIdentityProvider"/>.</param>
|
||||||
|
public UserApiController(IIdentityProvider identityProvider)
|
||||||
|
{
|
||||||
|
_identityProvider = identityProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the user's profile.
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet("profile")]
|
||||||
|
public IActionResult GetUserProfile()
|
||||||
|
{
|
||||||
|
var userId = _identityProvider.GetUserId();
|
||||||
|
var userName = _identityProvider.GetUserName();
|
||||||
|
|
||||||
|
return new JsonResult(new UserProfileResultModel()
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
AccountId = userId,
|
||||||
|
Username = userName,
|
||||||
|
XmppPassword = string.Empty,
|
||||||
|
DiscourseApiKey = string.Empty
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Does nothing for now since I believe the locker feature is deprecated.
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost("locker")]
|
||||||
|
public IActionResult PostLocker()
|
||||||
|
{
|
||||||
|
return SuccessResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Does nothing for now since I believe the locker feature is deprecated.
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet("locker")]
|
||||||
|
public IActionResult GetLocker()
|
||||||
|
{
|
||||||
|
return SuccessResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ public class TokenGrantResultModel : ResultModel
|
||||||
ExpiresIn = sessionDto.AccessTokenExpires.Ticks;
|
ExpiresIn = sessionDto.AccessTokenExpires.Ticks;
|
||||||
RefreshToken = sessionDto.RefreshToken;
|
RefreshToken = sessionDto.RefreshToken;
|
||||||
Scope = sessionDto.Scope.ToString().ToLowerInvariant();
|
Scope = sessionDto.Scope.ToString().ToLowerInvariant();
|
||||||
AccountId = sessionDto.UserId.ToString();
|
AccountId = sessionDto.UserId;
|
||||||
AccountName = sessionDto.UserName;
|
AccountName = sessionDto.UserName;
|
||||||
TokenType = "Bearer";
|
TokenType = "Bearer";
|
||||||
AccountRoles = sessionDto.Role.GetAccessibleRoles().Select(role => role.ToString().ToLowerInvariant()).ToList();
|
AccountRoles = sessionDto.Role.GetAccessibleRoles().Select(role => role.ToString().ToLowerInvariant()).ToList();
|
||||||
|
@ -79,7 +79,7 @@ public class TokenGrantResultModel : ResultModel
|
||||||
/// The user's id.
|
/// The user's id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("account_id")]
|
[JsonPropertyName("account_id")]
|
||||||
public string AccountId { get; set; }
|
public Guid AccountId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The user's name.
|
/// The user's name.
|
||||||
|
|
38
Astral.ApiServer/Models/UserProfileResultModel.cs
Normal file
38
Astral.ApiServer/Models/UserProfileResultModel.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// <copyright file="UserProfileResultModel.cs" company="alveus.dev">
|
||||||
|
// Copyright (c) alveus.dev. All rights reserved. Licensed under the MIT License.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Astral.ApiServer.Models.Common;
|
||||||
|
|
||||||
|
namespace Astral.ApiServer.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// User profile request result.
|
||||||
|
/// </summary>
|
||||||
|
public class UserProfileResultModel : ResultModel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Account id (Even used?).
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("accountId")]
|
||||||
|
public Guid AccountId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Username.
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("username")]
|
||||||
|
public string Username { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Discourse api key (Even used?).
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("discourse_api_key")]
|
||||||
|
public string DiscourseApiKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// XMPP Password (Even used?).
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("xmpp_password")]
|
||||||
|
public string XmppPassword { get; set; }
|
||||||
|
}
|
|
@ -36,6 +36,7 @@ builder.Services.AddHttpUserAgentMemoryCachedParser(opt =>
|
||||||
|
|
||||||
builder.Services.AddHostedService<StartupService>();
|
builder.Services.AddHostedService<StartupService>();
|
||||||
|
|
||||||
|
builder.Services.AddAstralApiServer();
|
||||||
builder.Services.AddAstralCore();
|
builder.Services.AddAstralCore();
|
||||||
builder.Services.AddAstralServices();
|
builder.Services.AddAstralServices();
|
||||||
builder.Services.AddAstralDAL();
|
builder.Services.AddAstralDAL();
|
||||||
|
|
45
Astral.ApiServer/Providers/IdentityProvider.cs
Normal file
45
Astral.ApiServer/Providers/IdentityProvider.cs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// <copyright file="IdentityProvider.cs" company="alveus.dev">
|
||||||
|
// Copyright (c) alveus.dev. All rights reserved. Licensed under the MIT License.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Astral.Services.Constants;
|
||||||
|
using Astral.Services.Interfaces;
|
||||||
|
using Injectio.Attributes;
|
||||||
|
|
||||||
|
namespace Astral.ApiServer.Providers;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[RegisterScoped]
|
||||||
|
public class IdentityProvider : IIdentityProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="IdentityProvider"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpContextAccessor">Instance of <see cref="IHttpContextAccessor"/>.</param>
|
||||||
|
public IdentityProvider(IHttpContextAccessor httpContextAccessor)
|
||||||
|
{
|
||||||
|
var claims = httpContextAccessor.HttpContext?.User.Claims;
|
||||||
|
if (claims is not null)
|
||||||
|
{
|
||||||
|
Claims = claims;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Session claims.
|
||||||
|
/// </summary>
|
||||||
|
private IEnumerable<Claim> Claims { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Guid GetUserId()
|
||||||
|
{
|
||||||
|
return Guid.TryParse(Claims.FirstOrDefault(c => c.Type == ClaimIds.UserId)?.Value, out var guid) ? guid : Guid.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string GetUserName()
|
||||||
|
{
|
||||||
|
return Claims.FirstOrDefault(c => c.Type == ClaimIds.UserName)?.Value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,8 +10,14 @@ namespace Astral.Services.Interfaces;
|
||||||
public interface IIdentityProvider
|
public interface IIdentityProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the user id of the requester.
|
/// Get the user id of the authorised agent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>String representing the user id, or null if none.</returns>
|
/// <returns>Guid representing the user id, or empty guid if none.</returns>
|
||||||
string GetRequestingUserId();
|
Guid GetUserId();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the username of the authorised agent.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Username, or null if none.</returns>
|
||||||
|
string GetUserName();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue