Cleaned up pagination in user and apikey controller. Extracted login start and start url generation to modular IOAuth2Provider interface. Improved login and register local oauth2 page
This commit is contained in:
@@ -28,8 +28,8 @@ public class ApiKeysController : Controller
|
||||
[HttpGet]
|
||||
[Authorize(Policy = "permissions:admin.apikeys.get")]
|
||||
public async Task<IPagedData<ApiKeyResponse>> Get(
|
||||
[FromQuery] int page,
|
||||
[FromQuery] [Range(1, 100)] int pageSize = 50
|
||||
[FromQuery] [Range(0, int.MaxValue)] int page,
|
||||
[FromQuery] [Range(1, 100)] int pageSize
|
||||
)
|
||||
{
|
||||
var count = await ApiKeyRepository.Get().CountAsync();
|
||||
|
||||
@@ -27,7 +27,7 @@ public class UsersController : Controller
|
||||
[Authorize(Policy = "permissions:admin.users.get")]
|
||||
public async Task<IPagedData<UserResponse>> Get(
|
||||
[FromQuery] [Range(0, int.MaxValue)] int page,
|
||||
[FromQuery] [Range(1, 100)] int pageSize = 50
|
||||
[FromQuery] [Range(1, 100)] int pageSize
|
||||
)
|
||||
{
|
||||
var count = await UserRepository.Get().CountAsync();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using MoonCore.Exceptions;
|
||||
using MoonCore.Extended.Abstractions;
|
||||
@@ -20,16 +20,11 @@ namespace Moonlight.ApiServer.Http.Controllers.Auth;
|
||||
public class AuthController : Controller
|
||||
{
|
||||
private readonly AppConfiguration Configuration;
|
||||
private readonly ILogger<AuthController> Logger;
|
||||
private readonly DatabaseRepository<User> UserRepository;
|
||||
private readonly IOAuth2Provider OAuth2Provider;
|
||||
|
||||
private readonly string RedirectUri;
|
||||
private readonly string EndpointUri;
|
||||
|
||||
public AuthController(
|
||||
AppConfiguration configuration,
|
||||
ILogger<AuthController> logger,
|
||||
DatabaseRepository<User> userRepository,
|
||||
IOAuth2Provider oAuth2Provider
|
||||
)
|
||||
@@ -37,36 +32,25 @@ public class AuthController : Controller
|
||||
UserRepository = userRepository;
|
||||
OAuth2Provider = oAuth2Provider;
|
||||
Configuration = configuration;
|
||||
Logger = logger;
|
||||
|
||||
RedirectUri = string.IsNullOrEmpty(Configuration.Authentication.OAuth2.AuthorizationRedirect)
|
||||
? Configuration.PublicUrl
|
||||
: Configuration.Authentication.OAuth2.AuthorizationRedirect;
|
||||
|
||||
EndpointUri = string.IsNullOrEmpty(Configuration.Authentication.OAuth2.AuthorizationEndpoint)
|
||||
? Configuration.PublicUrl + "/oauth2/authorize"
|
||||
: Configuration.Authentication.OAuth2.AuthorizationEndpoint;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("start")]
|
||||
public Task<LoginStartResponse> Start()
|
||||
public async Task<LoginStartResponse> Start()
|
||||
{
|
||||
var response = new LoginStartResponse()
|
||||
{
|
||||
ClientId = Configuration.Authentication.OAuth2.ClientId,
|
||||
RedirectUri = RedirectUri,
|
||||
Endpoint = EndpointUri
|
||||
};
|
||||
var url = await OAuth2Provider.Start();
|
||||
|
||||
return Task.FromResult(response);
|
||||
return new LoginStartResponse()
|
||||
{
|
||||
Url = url
|
||||
};
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("complete")]
|
||||
public async Task<LoginCompleteResponse> Complete([FromBody] LoginCompleteRequest request)
|
||||
{
|
||||
var user = await OAuth2Provider.Sync(request.Code);
|
||||
var user = await OAuth2Provider.Complete(request.Code);
|
||||
|
||||
if (user == null)
|
||||
throw new HttpApiException("Unable to load user data", 500);
|
||||
@@ -113,8 +97,8 @@ public class AuthController : Controller
|
||||
[HttpGet("check")]
|
||||
public async Task<CheckResponse> Check()
|
||||
{
|
||||
var userIdClaim = User.Claims.First(x => x.Type == "userId");
|
||||
var userId = int.Parse(userIdClaim.Value);
|
||||
var userIdStr = User.FindFirstValue("userId")!;
|
||||
var userId = int.Parse(userIdStr);
|
||||
var user = await UserRepository.Get().FirstAsync(x => x.Id == userId);
|
||||
|
||||
return new()
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>@Configuration.Title</title>
|
||||
<title>@Title</title>
|
||||
<base href="/"/>
|
||||
|
||||
@foreach (var style in Configuration.Styles)
|
||||
@foreach (var style in Styles)
|
||||
{
|
||||
<link rel="stylesheet" href="@style"/>
|
||||
}
|
||||
@@ -86,7 +86,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
@foreach (var script in Configuration.Scripts)
|
||||
@foreach (var script in Scripts)
|
||||
{
|
||||
<script src="@script"></script>
|
||||
}
|
||||
@@ -99,6 +99,8 @@
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter] public FrontendConfiguration Configuration { get; set; }
|
||||
[Parameter] public string Title { get; set; }
|
||||
[Parameter] public string[] Scripts { get; set; }
|
||||
[Parameter] public string[] Styles { get; set; }
|
||||
[Parameter] public Theme? Theme { get; set; }
|
||||
}
|
||||
|
||||
@@ -3,55 +3,50 @@
|
||||
<title>Login into your account</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/css/style.min.css"/>
|
||||
</head>
|
||||
<body class="h-full">
|
||||
|
||||
<div class="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
|
||||
<div class="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<img class="mx-auto h-14 w-auto" src="/svg/logo.svg" alt="Moonlight">
|
||||
<h2 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-gray-100">Login into your account</h2>
|
||||
</div>
|
||||
|
||||
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px]">
|
||||
<div class="bg-gray-800 px-6 py-12 shadow sm:rounded-lg sm:px-12">
|
||||
|
||||
@if (!string.IsNullOrEmpty(ErrorMessage))
|
||||
{
|
||||
<div class="rounded-lg bg-red-500 p-5 text-center text-white mb-8">
|
||||
@ErrorMessage
|
||||
</div>
|
||||
}
|
||||
|
||||
<form class="space-y-6" method="POST">
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium leading-6 text-gray-100">Email address</label>
|
||||
<div class="mt-2">
|
||||
<input id="email" name="email" type="email" autocomplete="email" required class="block bg-white/5 w-full rounded-md border-0 py-1.5 text-gray-100 shadow-sm ring-1 ring-inset ring-gray-700 placeholder:text-gray-600 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||
<div class="flex h-auto min-h-screen items-center justify-center overflow-x-hidden bg-background py-10">
|
||||
<div class="relative flex items-center justify-center px-4 sm:px-6 lg:px-8">
|
||||
<div
|
||||
class="bg-base-100 shadow-base-300/20 z-1 w-full space-y-6 rounded-xl p-6 shadow-md sm:min-w-md lg:p-8">
|
||||
<div class="flex justify-center items-center gap-3">
|
||||
<img src="/_content/Moonlight.Client/svg/logo.svg" class="size-12" alt="brand-logo"/>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<h3 class="text-base-content mb-1.5 text-2xl font-semibold">Login into your account</h3>
|
||||
<p class="text-base-content/80">After logging in you will be able to manage your services</p>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
|
||||
@if (!string.IsNullOrEmpty(ErrorMessage))
|
||||
{
|
||||
<div class="alert alert-error text-center">
|
||||
@ErrorMessage
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password" class="block text-sm font-medium leading-6 text-gray-100">Password</label>
|
||||
<div class="mt-2">
|
||||
<input id="password" name="password" type="password" autocomplete="current-password" required class="block bg-white/5 w-full rounded-md border-0 py-1.5 text-gray-100 shadow-sm ring-1 ring-inset ring-gray-700 placeholder:text-gray-600 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||
}
|
||||
|
||||
<form class="mb-4 space-y-4" method="post">
|
||||
<div>
|
||||
<label class="label-text" for="email">Email address</label>
|
||||
<input type="email" name="email" placeholder="Enter your email address" class="input" id="email"
|
||||
required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button type="submit" class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
|
||||
Login
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div>
|
||||
<label class="label-text" for="password">Password</label>
|
||||
<input class="input" name="password" id="password" type="password" placeholder="············"
|
||||
required/>
|
||||
</div>
|
||||
<button class="btn btn-lg btn-primary btn-gradient btn-block">Login</button>
|
||||
</form>
|
||||
<p class="text-base-content/80 mb-4 text-center">
|
||||
No account?
|
||||
<a href="?client_id=@(ClientId)&redirect_uri=@(RedirectUri)&response_type=@(ResponseType)&view=register"
|
||||
class="link link-animated link-primary font-normal">Create an account</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="mt-5 text-center text-sm text-gray-500">
|
||||
No account?
|
||||
<a href="?client_id=@(ClientId)&redirect_uri=@(RedirectUri)&response_type=@(ResponseType)&view=register" class="font-semibold leading-6 text-indigo-600 hover:text-indigo-500">
|
||||
Register
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,63 +3,57 @@
|
||||
<title>Register a new account</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/css/style.min.css"/>
|
||||
</head>
|
||||
<body class="h-full">
|
||||
|
||||
<div class="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
|
||||
<div class="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<img class="mx-auto h-14 w-auto" src="/svg/logo.svg" alt="Moonlight">
|
||||
<h2 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-gray-100">Create your account</h2>
|
||||
</div>
|
||||
<div class="flex h-auto min-h-screen items-center justify-center overflow-x-hidden bg-background py-10">
|
||||
<div class="relative flex items-center justify-center px-4 sm:px-6 lg:px-8">
|
||||
<div
|
||||
class="bg-base-100 shadow-base-300/20 z-1 w-full space-y-6 rounded-xl p-6 shadow-md sm:min-w-md lg:p-8">
|
||||
<div class="flex justify-center items-center gap-3">
|
||||
<img src="/_content/Moonlight.Client/svg/logo.svg" class="size-12" alt="brand-logo"/>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<h3 class="text-base-content mb-1.5 text-2xl font-semibold">Register a new account</h3>
|
||||
<p class="text-base-content/80">After signing up you will be able to manage your services</p>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
|
||||
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px]">
|
||||
<div class="bg-gray-800 px-6 py-12 shadow sm:rounded-lg sm:px-12">
|
||||
|
||||
@if (!string.IsNullOrEmpty(ErrorMessage))
|
||||
{
|
||||
<div class="rounded-lg bg-red-500 p-5 text-center text-white mb-8">
|
||||
@ErrorMessage
|
||||
</div>
|
||||
}
|
||||
|
||||
<form class="space-y-6" method="POST">
|
||||
<div>
|
||||
<label for="username" class="block text-sm font-medium leading-6 text-gray-100">Username</label>
|
||||
<div class="mt-2">
|
||||
<input id="username" name="username" type="text" required class="block bg-white/5 w-full rounded-md border-0 py-1.5 text-gray-100 shadow-sm ring-1 ring-inset ring-gray-700 placeholder:text-gray-600 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||
@if (!string.IsNullOrEmpty(ErrorMessage))
|
||||
{
|
||||
<div class="alert alert-error text-center">
|
||||
@ErrorMessage
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium leading-6 text-gray-100">Email address</label>
|
||||
<div class="mt-2">
|
||||
<input id="email" name="email" type="email" autocomplete="email" required class="block bg-white/5 w-full rounded-md border-0 py-1.5 text-gray-100 shadow-sm ring-1 ring-inset ring-gray-700 placeholder:text-gray-600 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||
<form class="mb-4 space-y-4" method="post">
|
||||
<div>
|
||||
<label class="label-text" for="username">Username</label>
|
||||
<input type="text" name="username" placeholder="Enter your username" class="input" id="username"
|
||||
required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password" class="block text-sm font-medium leading-6 text-gray-100">Password</label>
|
||||
<div class="mt-2">
|
||||
<input id="password" name="password" type="password" autocomplete="current-password" required class="block bg-white/5 w-full rounded-md border-0 py-1.5 text-gray-100 shadow-sm ring-1 ring-inset ring-gray-700 placeholder:text-gray-600 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||
<div>
|
||||
<label class="label-text" for="email">Email address</label>
|
||||
<input type="email" name="email" placeholder="Enter your email address" class="input" id="email"
|
||||
required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button type="submit" class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
|
||||
Create your account
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div>
|
||||
<label class="label-text" for="password">Password</label>
|
||||
<input class="input" name="password" id="password" type="password" placeholder="············"
|
||||
required/>
|
||||
</div>
|
||||
<button class="btn btn-lg btn-primary btn-gradient btn-block">Register</button>
|
||||
</form>
|
||||
<p class="text-base-content/80 mb-4 text-center">
|
||||
Already registered?
|
||||
<a href="?client_id=@(ClientId)&redirect_uri=@(RedirectUri)&response_type=@(ResponseType)&view=login"
|
||||
class="link link-animated link-primary font-normal">Login into your account</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="mt-5 text-center text-sm text-gray-500">
|
||||
Already registered?
|
||||
<a href="?client_id=@(ClientId)&redirect_uri=@(RedirectUri)&response_type=@(ResponseType)&view=login" class="font-semibold leading-6 text-indigo-600 hover:text-indigo-500">Login</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user