Improved oauth2 ui design
This commit is contained in:
@@ -1,18 +1,19 @@
|
|||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using MoonCore.Exceptions;
|
using MoonCore.Exceptions;
|
||||||
using MoonCore.Extended.Abstractions;
|
using MoonCore.Extended.Abstractions;
|
||||||
using MoonCore.Extended.OAuth2.AuthServer;
|
using MoonCore.Extended.OAuth2.AuthServer;
|
||||||
using MoonCore.Extended.OAuth2.Models;
|
using MoonCore.Extended.OAuth2.Models;
|
||||||
using MoonCore.Services;
|
|
||||||
using Moonlight.ApiServer.Configuration;
|
|
||||||
using Moonlight.ApiServer.Database.Entities;
|
using Moonlight.ApiServer.Database.Entities;
|
||||||
|
using Moonlight.ApiServer.Http.Controllers.OAuth2.Pages;
|
||||||
using Moonlight.ApiServer.Services;
|
using Moonlight.ApiServer.Services;
|
||||||
using Moonlight.Shared.Http.Responses.OAuth2;
|
using Moonlight.Shared.Http.Responses.OAuth2;
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Http.Controllers.OAuth2;
|
namespace Moonlight.ApiServer.Http.Controllers.OAuth2;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("oauth2")]
|
[Microsoft.AspNetCore.Mvc.Route("oauth2")]
|
||||||
public class OAuth2Controller : Controller
|
public class OAuth2Controller : Controller
|
||||||
{
|
{
|
||||||
private readonly OAuth2Service OAuth2Service;
|
private readonly OAuth2Service OAuth2Service;
|
||||||
@@ -31,7 +32,8 @@ public class OAuth2Controller : Controller
|
|||||||
public async Task Authorize(
|
public async Task Authorize(
|
||||||
[FromQuery(Name = "response_type")] string responseType,
|
[FromQuery(Name = "response_type")] string responseType,
|
||||||
[FromQuery(Name = "client_id")] string clientId,
|
[FromQuery(Name = "client_id")] string clientId,
|
||||||
[FromQuery(Name = "redirect_uri")] string redirectUri
|
[FromQuery(Name = "redirect_uri")] string redirectUri,
|
||||||
|
[FromQuery(Name = "action")] string action = "login"
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (responseType != "code")
|
if (responseType != "code")
|
||||||
@@ -41,20 +43,29 @@ public class OAuth2Controller : Controller
|
|||||||
throw new HttpApiException("Invalid authorization request", 400);
|
throw new HttpApiException("Invalid authorization request", 400);
|
||||||
|
|
||||||
Response.StatusCode = 200;
|
Response.StatusCode = 200;
|
||||||
await Response.WriteAsync(
|
|
||||||
"<h1>Login lol</h1><br />" +
|
if (action == "register")
|
||||||
"<br />" +
|
{
|
||||||
"<br />" +
|
await Response.WriteAsync(
|
||||||
"<form method=\"post\">" +
|
await RenderPage<Register>(parmeters =>
|
||||||
"<label for=\"email\">Email:</label>" +
|
{
|
||||||
"<input type=\"email\" id=\"email\" name=\"email\"><br>" +
|
parmeters.Add("ClientId", clientId);
|
||||||
"<br>" +
|
parmeters.Add("ResponseType", responseType);
|
||||||
"<label for=\"password\">Password:</label>" +
|
parmeters.Add("RedirectUri", redirectUri);
|
||||||
"<input type=\"password\" id=\"password\" name=\"password\"><br>" +
|
})
|
||||||
"<br>" +
|
);
|
||||||
"<input type=\"submit\" value=\"Submit\">" +
|
}
|
||||||
"</form>"
|
else
|
||||||
);
|
{
|
||||||
|
await Response.WriteAsync(
|
||||||
|
await RenderPage<Login>(parmeters =>
|
||||||
|
{
|
||||||
|
parmeters.Add("ClientId", clientId);
|
||||||
|
parmeters.Add("ResponseType", responseType);
|
||||||
|
parmeters.Add("RedirectUri", redirectUri);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("authorize")]
|
[HttpPost("authorize")]
|
||||||
@@ -189,4 +200,22 @@ public class OAuth2Controller : Controller
|
|||||||
Email = currentUser.Email
|
Email = currentUser.Email
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<string> RenderPage<T>(Action<Dictionary<string, object>>? onConfigureParameters = null) where T : ComponentBase
|
||||||
|
{
|
||||||
|
var parameters = new Dictionary<string, object>();
|
||||||
|
onConfigureParameters?.Invoke(parameters);
|
||||||
|
|
||||||
|
await using var htmlRenderer = new HtmlRenderer(HttpContext.RequestServices, HttpContext.RequestServices.GetRequiredService<ILoggerFactory>());
|
||||||
|
|
||||||
|
var html = await htmlRenderer.Dispatcher.InvokeAsync(async () =>
|
||||||
|
{
|
||||||
|
var parameterView = ParameterView.FromDictionary(parameters!);
|
||||||
|
var output = await htmlRenderer.RenderComponentAsync<T>(parameterView);
|
||||||
|
|
||||||
|
return output.ToHtmlString();
|
||||||
|
});
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Login to your moonlight 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>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
||||||
|
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
|
<img class="mx-auto h-10 w-auto" src="https://gamecp.masuowo.xyz/api/core/asset/Core/svg/logo.svg" alt="Your Company">
|
||||||
|
<h2 class="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">Sign in to your account</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
|
<form class="space-y-6" action="#" method="POST">
|
||||||
|
<div>
|
||||||
|
<label for="email" class="block text-sm font-medium leading-6 text-gray-900">Email address</label>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input id="email" name="email" type="email" autocomplete="email" required class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<label for="password" class="block text-sm font-medium leading-6 text-gray-900">Password</label>
|
||||||
|
<div class="text-sm">
|
||||||
|
<a href="#" class="font-semibold text-indigo-600 hover:text-indigo-500">Forgot password?</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input id="password" name="password" type="password" autocomplete="current-password" required class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||||
|
</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">Sign in</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="mt-10 text-center text-sm text-gray-500">
|
||||||
|
Not a member?
|
||||||
|
|
||||||
|
@{
|
||||||
|
var registerUrl = $"?response_type={ResponseType}&client_id={ClientId}&redirect_uri={RedirectUri}&action=register";
|
||||||
|
}
|
||||||
|
|
||||||
|
<a href="@registerUrl" class="font-semibold leading-6 text-indigo-600 hover:text-indigo-500">Register now</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public string ClientId { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string RedirectUri { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string ResponseType { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Register your moonlight 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>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
||||||
|
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
|
<img class="mx-auto h-10 w-auto" src="https://gamecp.masuowo.xyz/api/core/asset/Core/svg/logo.svg" alt="Your Company">
|
||||||
|
<h2 class="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">Create your account</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
|
<form class="space-y-6" action="#" method="POST">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="email" class="block text-sm font-medium leading-6 text-gray-900">Username</label>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input id="username" name="username" type="text" autocomplete="username" required class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="email" class="block text-sm font-medium leading-6 text-gray-900">Email address</label>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input id="email" name="email" type="email" autocomplete="email" required class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<label for="password" class="block text-sm font-medium leading-6 text-gray-900">Password</label>
|
||||||
|
<div class="text-sm">
|
||||||
|
<a href="#" class="font-semibold text-indigo-600 hover:text-indigo-500">Forgot password?</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input id="password" name="password" type="password" autocomplete="current-password" required class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||||
|
</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">Sign up</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="mt-10 text-center text-sm text-gray-500">
|
||||||
|
Already a member?
|
||||||
|
|
||||||
|
@{
|
||||||
|
var loginUrl = $"?response_type={ResponseType}&client_id={ClientId}&redirect_uri={RedirectUri}&action=login";
|
||||||
|
}
|
||||||
|
|
||||||
|
<a href="@loginUrl" class="font-semibold leading-6 text-indigo-600 hover:text-indigo-500">Login now</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public string ClientId { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string RedirectUri { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string ResponseType { get; set; }
|
||||||
|
}
|
||||||
@@ -108,6 +108,8 @@ else
|
|||||||
{
|
{
|
||||||
IsHandlingDone = true;
|
IsHandlingDone = true;
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
|
|
||||||
|
Navigation.NavigateTo("/", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +122,9 @@ else
|
|||||||
$"&redirect_uri={authStartData.RedirectUri}" +
|
$"&redirect_uri={authStartData.RedirectUri}" +
|
||||||
$"&response_type=code";
|
$"&response_type=code";
|
||||||
|
|
||||||
|
Navigation.NavigateTo(uri, true);
|
||||||
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await WindowService.Open(
|
await WindowService.Open(
|
||||||
|
|||||||
Reference in New Issue
Block a user