mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Add ApiKeys authentication
This commit is contained in:
parent
bf281820b9
commit
86955cf0cb
@ -19,6 +19,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Abstractions.Controllers;
|
using Kyoo.Abstractions.Controllers;
|
||||||
using Kyoo.Abstractions.Models.Permissions;
|
using Kyoo.Abstractions.Models.Permissions;
|
||||||
@ -30,6 +31,7 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
namespace Kyoo.Authentication
|
namespace Kyoo.Authentication
|
||||||
{
|
{
|
||||||
@ -169,22 +171,48 @@ namespace Kyoo.Authentication
|
|||||||
|
|
||||||
string permStr = $"{permission.ToLower()}.{kind.ToString()!.ToLower()}";
|
string permStr = $"{permission.ToLower()}.{kind.ToString()!.ToLower()}";
|
||||||
string overallStr = $"{_group.ToString().ToLower()}.{kind.ToString()!.ToLower()}";
|
string overallStr = $"{_group.ToString().ToLower()}.{kind.ToString()!.ToLower()}";
|
||||||
AuthenticateResult res = await context.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
|
AuthenticateResult res = _ApiKeyCheck(context);
|
||||||
|
if (res.None)
|
||||||
|
res = await context.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
|
||||||
if (res.Succeeded)
|
if (res.Succeeded)
|
||||||
{
|
{
|
||||||
ICollection<string> permissions = res.Principal.GetPermissions();
|
ICollection<string> permissions = res.Principal.GetPermissions();
|
||||||
if (permissions.All(x => x != permStr && x != overallStr))
|
if (permissions.All(x => x != permStr && x != overallStr))
|
||||||
context.Result = _ErrorResult($"Missing permission {permStr} or {overallStr}", StatusCodes.Status403Forbidden);
|
context.Result = _ErrorResult($"Missing permission {permStr} or {overallStr}", StatusCodes.Status403Forbidden);
|
||||||
}
|
}
|
||||||
else
|
else if (res.None)
|
||||||
{
|
{
|
||||||
ICollection<string> permissions = _options.CurrentValue.Default ?? Array.Empty<string>();
|
ICollection<string> permissions = _options.CurrentValue.Default ?? Array.Empty<string>();
|
||||||
if (res.Failure != null || permissions.All(x => x != permStr && x != overallStr))
|
if (permissions.All(x => x != permStr && x != overallStr))
|
||||||
{
|
{
|
||||||
context.Result = _ErrorResult("Token non present or invalid (it may have expired). " +
|
context.Result = _ErrorResult($"Unlogged user does not have permission {permStr} or {overallStr}", StatusCodes.Status401Unauthorized);
|
||||||
$"Unlogged user does not have permission {permStr} or {overallStr}", StatusCodes.Status401Unauthorized);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (res.Failure != null)
|
||||||
|
context.Result = _ErrorResult(res.Failure.Message, StatusCodes.Status403Forbidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthenticateResult _ApiKeyCheck(ActionContext context)
|
||||||
|
{
|
||||||
|
if (!context.HttpContext.Request.Headers.TryGetValue("X-API-Key", out StringValues apiKey))
|
||||||
|
return AuthenticateResult.NoResult();
|
||||||
|
if (!_options.CurrentValue.ApiKeys.Contains<string>(apiKey))
|
||||||
|
return AuthenticateResult.Fail("Invalid API-Key.");
|
||||||
|
return AuthenticateResult.Success(
|
||||||
|
new AuthenticationTicket(
|
||||||
|
new ClaimsPrincipal(
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new ClaimsIdentity(new[]
|
||||||
|
{
|
||||||
|
// TODO: Make permission configurable, for now every APIKEY as all permissions.
|
||||||
|
new Claim(Claims.Permissions, string.Join(',', PermissionOption.Admin))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"apikey"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ namespace Kyoo.Authentication.Views
|
|||||||
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(RequestError))]
|
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(RequestError))]
|
||||||
public async Task<ActionResult<JwtToken>> Login([FromBody] LoginRequest request)
|
public async Task<ActionResult<JwtToken>> Login([FromBody] LoginRequest request)
|
||||||
{
|
{
|
||||||
User user = await _users.GetOrDefault(x => x.Username == request.Username);
|
User? user = await _users.GetOrDefault(x => x.Username == request.Username);
|
||||||
if (user == null || !BCryptNet.Verify(request.Password, user.Password))
|
if (user == null || !BCryptNet.Verify(request.Password, user.Password))
|
||||||
return Forbid(new RequestError("The user and password does not match."));
|
return Forbid(new RequestError("The user and password does not match."));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user