Merge pull request #124 from Moonlight-Panel/RewriteOAuth2System

Rewritten the oauth2 system to be more modular
This commit is contained in:
Marcel Baumgartner 2023-05-21 20:32:02 +02:00 committed by GitHub
commit 4e1d673efa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 355 additions and 379 deletions

View file

@ -30,4 +30,17 @@ public static class StringHelper
return result;
}
public static string CapitalizeFirstCharacter(string input)
{
if (string.IsNullOrEmpty(input))
{
return input;
}
char firstChar = char.ToUpper(input[0]);
string restOfString = input.Substring(1);
return firstChar + restOfString;
}
}

View file

@ -1,12 +1,6 @@
using Logging.Net;
using Microsoft.AspNetCore.Mvc;
using Moonlight.App.Exceptions;
using Moonlight.App.Helpers;
using Moonlight.App.Models.Misc;
using Moonlight.App.Repositories;
using Moonlight.App.Services;
using Moonlight.App.Services.OAuth2;
using Moonlight.App.Services.Sessions;
namespace Moonlight.App.Http.Controllers.Api.Moonlight;
@ -14,130 +8,37 @@ namespace Moonlight.App.Http.Controllers.Api.Moonlight;
[Route("api/moonlight/oauth2")]
public class OAuth2Controller : Controller
{
private readonly GoogleOAuth2Service GoogleOAuth2Service;
private readonly DiscordOAuth2Service DiscordOAuth2Service;
private readonly UserRepository UserRepository;
private readonly UserService UserService;
private readonly OAuth2Service OAuth2Service;
private readonly DateTimeService DateTimeService;
public OAuth2Controller(
GoogleOAuth2Service googleOAuth2Service,
UserRepository userRepository,
UserService userService,
DiscordOAuth2Service discordOAuth2Service, DateTimeService dateTimeService)
public OAuth2Controller(UserService userService, OAuth2Service oAuth2Service, DateTimeService dateTimeService)
{
GoogleOAuth2Service = googleOAuth2Service;
UserRepository = userRepository;
UserService = userService;
DiscordOAuth2Service = discordOAuth2Service;
OAuth2Service = oAuth2Service;
DateTimeService = dateTimeService;
}
[HttpGet("google")]
public async Task<ActionResult> Google([FromQuery] string code)
[HttpGet("{id}")]
public async Task<ActionResult> Hande([FromRoute] string id, [FromQuery] string code)
{
try
{
var userData = await GoogleOAuth2Service.HandleCode(code);
var user = await OAuth2Service.HandleCode(id, code);
if (userData == null)
return Redirect("/login");
try
Response.Cookies.Append("token", await UserService.GenerateToken(user), new()
{
var user = UserRepository.Get().FirstOrDefault(x => x.Email == userData.Email);
Expires = new DateTimeOffset(DateTimeService.GetCurrent().AddDays(10))
});
string token;
if (user == null)
{
token = await UserService.Register(
userData.Email,
StringHelper.GenerateString(32),
userData.FirstName,
userData.LastName
);
}
else
{
token = await UserService.GenerateToken(user, true);
}
Response.Cookies.Append("token", token, new ()
{
Expires = new DateTimeOffset(DateTimeService.GetCurrent().AddDays(10))
});
return Redirect("/");
}
catch (Exception e)
{
Logger.Warn(e.Message);
return Redirect("/login");
}
return Redirect("/");
}
catch (Exception e)
{
Logger.Warn("An unexpected error occured while handling oauth2");
Logger.Warn(e.Message);
return BadRequest();
}
}
[HttpGet("discord")]
public async Task<ActionResult> Discord([FromQuery] string code)
{
try
{
var userData = await DiscordOAuth2Service.HandleCode(code);
if (userData == null)
return Redirect("/login");
try
{
var user = UserRepository.Get().FirstOrDefault(x => x.Email == userData.Email);
string token;
if (user == null)
{
token = await UserService.Register(
userData.Email,
StringHelper.GenerateString(32),
userData.FirstName,
userData.LastName
);
var newUser = UserRepository
.Get()
.First(x => x.Email == userData.Email);
newUser.Status = UserStatus.DataPending;
UserRepository.Update(newUser);
}
else
{
token = await UserService.GenerateToken(user, true);
}
Response.Cookies.Append("token", token, new ()
{
Expires = new DateTimeOffset(DateTimeService.GetCurrent().AddDays(10))
});
return Redirect("/");
}
catch (Exception e)
{
Logger.Warn(e.Message);
return Redirect("/login");
}
}
catch (Exception e)
{
Logger.Warn(e.Message);
return BadRequest();
return Redirect("/login");
}
}
}

View file

@ -0,0 +1,8 @@
namespace Moonlight.App.Models.Misc;
public class OAuth2ProviderConfig
{
public string Id { get; set; } = "";
public string ClientId { get; set; } = "";
public string ClientSecret { get; set; } = "";
}

View file

@ -0,0 +1,15 @@
using Moonlight.App.Database.Entities;
using Moonlight.App.Models.Misc;
namespace Moonlight.App.OAuth2;
public abstract class OAuth2Provider
{
public OAuth2ProviderConfig Config { get; set; }
public string Url { get; set; }
public IServiceScopeFactory ServiceScopeFactory { get; set; }
public string DisplayName { get; set; }
public abstract Task<string> GetUrl();
public abstract Task<User> HandleCode(string code);
}

View file

@ -0,0 +1,122 @@
using System.Text;
using Logging.Net;
using Moonlight.App.Database.Entities;
using Moonlight.App.Exceptions;
using Moonlight.App.Helpers;
using Moonlight.App.Models.Misc;
using Moonlight.App.Repositories;
using Moonlight.App.Services;
using RestSharp;
namespace Moonlight.App.OAuth2.Providers;
public class DiscordOAuth2Provider : OAuth2Provider
{
public override Task<string> GetUrl()
{
string url = $"https://discord.com/api/oauth2/authorize?client_id={Config.ClientId}" +
$"&redirect_uri={Url}/api/moonlight/oauth2/discord" +
"&response_type=code&scope=identify%20email";
return Task.FromResult(
url
);
}
public override async Task<User> HandleCode(string code)
{
// Endpoints
var endpoint = Url + "/api/moonlight/oauth2/discord";
var discordUserDataEndpoint = "https://discordapp.com/api/users/@me";
var discordEndpoint = "https://discordapp.com/api/oauth2/token";
// Generate access token
using var client = new RestClient();
var request = new RestRequest(discordEndpoint);
request.AddParameter("client_id", Config.ClientId);
request.AddParameter("client_secret", Config.ClientSecret);
request.AddParameter("grant_type", "authorization_code");
request.AddParameter("code", code);
request.AddParameter("redirect_uri", endpoint);
var response = await client.ExecutePostAsync(request);
if (!response.IsSuccessful)
{
Logger.Warn("Error verifying oauth2 code");
Logger.Warn(response.ErrorMessage);
throw new DisplayException("An error occured while verifying oauth2 code");
}
// parse response
var data = new ConfigurationBuilder().AddJsonStream(
new MemoryStream(Encoding.ASCII.GetBytes(response.Content!))
).Build();
var accessToken = data.GetValue<string>("access_token");
// Now, we will call the discord api with our access token to get the data we need
var getRequest = new RestRequest(discordUserDataEndpoint);
getRequest.AddHeader("Authorization", $"Bearer {accessToken}");
var getResponse = await client.ExecuteGetAsync(getRequest);
if (!getResponse.IsSuccessful)
{
Logger.Warn("An unexpected error occured while fetching user data from remote api");
Logger.Warn(getResponse.ErrorMessage);
throw new DisplayException("An unexpected error occured while fetching user data from remote api");
}
// Parse response
var getData = new ConfigurationBuilder().AddJsonStream(
new MemoryStream(Encoding.ASCII.GetBytes(getResponse.Content!))
).Build();
var email = getData.GetValue<string>("email");
var id = getData.GetValue<ulong>("id");
// Handle data
using var scope = ServiceScopeFactory.CreateScope();
var userRepo = scope.ServiceProvider.GetRequiredService<Repository<User>>();
var userService = scope.ServiceProvider.GetRequiredService<UserService>();
if (userRepo.Get().Any(x => x.Email == email))
{
var user = userRepo.Get().First(x => x.Email == email);
user.DiscordId = id;
userRepo.Update(user);
return user;
}
else
{
await userService.Register(
email,
StringHelper.GenerateString(32),
"User",
"User"
);
var user = userRepo.Get().First(x => x.Email == email);
user.Status = UserStatus.DataPending;
user.DiscordId = id;
userRepo.Update(user);
return user;
}
}
}

View file

@ -3,70 +3,42 @@ using Logging.Net;
using Moonlight.App.ApiClients.Google.Requests;
using Moonlight.App.Database.Entities;
using Moonlight.App.Exceptions;
using Moonlight.App.Helpers;
using Moonlight.App.Models.Misc;
using Moonlight.App.Repositories;
using Moonlight.App.Services;
using RestSharp;
namespace Moonlight.App.Services.OAuth2;
namespace Moonlight.App.OAuth2.Providers;
public class GoogleOAuth2Service
public class GoogleOAuth2Provider : OAuth2Provider
{
private readonly bool EnableGoogle;
private readonly string GoogleClientId;
private readonly string GoogleClientSecret;
private readonly bool EnableOverrideUrl;
private readonly string OverrideUrl;
private readonly string AppUrl;
public GoogleOAuth2Service(ConfigService configService)
public override Task<string> GetUrl()
{
var config = configService
.GetSection("Moonlight")
.GetSection("OAuth2");
EnableGoogle = config
.GetSection("Google")
.GetValue<bool>("Enable");
if (EnableGoogle)
{
GoogleClientId = config.GetSection("Google").GetValue<string>("ClientId");
GoogleClientSecret = config.GetSection("Google").GetValue<string>("ClientSecret");
}
EnableOverrideUrl = config.GetValue<bool>("EnableOverrideUrl");
if (EnableOverrideUrl)
OverrideUrl = config.GetValue<string>("OverrideUrl");
AppUrl = configService.GetSection("Moonlight").GetValue<string>("AppUrl");
}
public Task<string> GetUrl()
{
if (!EnableGoogle)
throw new DisplayException("Google OAuth2 not enabled");
var endpoint = GetBaseUrl() + "/api/moonlight/oauth2/google";
var endpoint = Url + "/api/moonlight/oauth2/google";
var scope = "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email";
return Task.FromResult(
$"https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={GoogleClientId}&redirect_uri={endpoint}&scope={scope}"
$"https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={Config.ClientId}&redirect_uri={endpoint}&scope={scope}"
);
}
public async Task<User?> HandleCode(string code)
public override async Task<User> HandleCode(string code)
{
// Generate access token
var endpoint = GetBaseUrl() + "/api/moonlight/oauth2/google";
// Endpoints
var endpoint = Url + "/api/moonlight/oauth2/google";
var googleEndpoint = "https://oauth2.googleapis.com/token";
var googlePeopleEndpoint = "https://people.googleapis.com/v1/people/me";
// Generate access token
// Setup payload
var payload = new GoogleOAuth2CodePayload()
{
Code = code,
RedirectUri = endpoint,
ClientId = GoogleClientId,
ClientSecret = GoogleClientSecret
ClientId = Config.ClientId,
ClientSecret = Config.ClientSecret
};
using var client = new RestClient();
@ -77,9 +49,9 @@ public class GoogleOAuth2Service
if (!response.IsSuccessful)
{
//TODO: Maybe add better error handling
Logger.Debug("oAuth2 validate error: " + response.Content!);
return null;
Logger.Warn("Error verifying oauth2 code");
Logger.Warn(response.ErrorMessage);
throw new DisplayException("An error occured while verifying oauth2 code");
}
// parse response
@ -91,8 +63,6 @@ public class GoogleOAuth2Service
var accessToken = data.GetValue<string>("access_token");
// Now, we will call the google api with our access token to get the data we need
var googlePeopleEndpoint = "https://people.googleapis.com/v1/people/me";
var getRequest = new RestRequest(googlePeopleEndpoint);
getRequest.AddHeader("Authorization", $"Bearer {accessToken}");
@ -102,9 +72,10 @@ public class GoogleOAuth2Service
if (!getResponse.IsSuccessful)
{
//TODO: Maybe add better error handling
Logger.Debug("OAuth2 api access error: " + getResponse.Content!);
return null;
Logger.Warn("An unexpected error occured while fetching user data from remote api");
Logger.Warn(getResponse.ErrorMessage);
throw new DisplayException("An unexpected error occured while fetching user data from remote api");
}
// Parse response
@ -131,19 +102,29 @@ public class GoogleOAuth2Service
.First()
.GetValue<string>("value");
return new()
using var scope = ServiceScopeFactory.CreateScope();
var userRepo = scope.ServiceProvider.GetRequiredService<Repository<User>>();
var userService = scope.ServiceProvider.GetRequiredService<UserService>();
if (userRepo.Get().Any(x => x.Email == email))
{
Email = email,
FirstName = firstName,
LastName = lastName
};
}
var user = userRepo.Get().First(x => x.Email == email);
return user;
}
else
{
await userService.Register(
email,
StringHelper.GenerateString(32),
firstName,
lastName
);
private string GetBaseUrl()
{
if (EnableOverrideUrl)
return OverrideUrl;
var user = userRepo.Get().First(x => x.Email == email);
return AppUrl;
return user;
}
}
}

View file

@ -1,129 +0,0 @@
using System.Text;
using Logging.Net;
using Moonlight.App.Database.Entities;
using Moonlight.App.Exceptions;
using Moonlight.App.Models.Misc;
using RestSharp;
namespace Moonlight.App.Services.OAuth2;
public class DiscordOAuth2Service
{
private readonly bool Enable;
private readonly string ClientId;
private readonly string ClientSecret;
private readonly bool EnableOverrideUrl;
private readonly string OverrideUrl;
private readonly string AppUrl;
public DiscordOAuth2Service(ConfigService configService)
{
var config = configService
.GetSection("Moonlight")
.GetSection("OAuth2");
Enable = config
.GetSection("Discord")
.GetValue<bool>("Enable");
if (Enable)
{
ClientId = config.GetSection("Discord").GetValue<string>("ClientId");
ClientSecret = config.GetSection("Discord").GetValue<string>("ClientSecret");
}
EnableOverrideUrl = config.GetValue<bool>("EnableOverrideUrl");
if (EnableOverrideUrl)
OverrideUrl = config.GetValue<string>("OverrideUrl");
AppUrl = configService.GetSection("Moonlight").GetValue<string>("AppUrl");
}
public Task<string> GetUrl()
{
if (!Enable)
throw new DisplayException("Discord OAuth2 not enabled");
string url = $"https://discord.com/api/oauth2/authorize?client_id={ClientId}" +
$"&redirect_uri={GetBaseUrl()}/api/moonlight/oauth2/discord" +
"&response_type=code&scope=identify%20email";
return Task.FromResult(
url
);
}
public async Task<User?> HandleCode(string code)
{
// Generate access token
var endpoint = GetBaseUrl() + "/api/moonlight/oauth2/discord";
var discordEndpoint = "https://discordapp.com/api/oauth2/token";
using var client = new RestClient();
var request = new RestRequest(discordEndpoint);
request.AddParameter("client_id", ClientId);
request.AddParameter("client_secret", ClientSecret);
request.AddParameter("grant_type", "authorization_code");
request.AddParameter("code", code);
request.AddParameter("redirect_uri", endpoint);
var response = await client.ExecutePostAsync(request);
if (!response.IsSuccessful)
{
//TODO: Maybe add better error handling
Logger.Debug("oAuth2 validate error: " + response.Content!);
return null;
}
// parse response
var data = new ConfigurationBuilder().AddJsonStream(
new MemoryStream(Encoding.ASCII.GetBytes(response.Content!))
).Build();
var accessToken = data.GetValue<string>("access_token");
// Now, we will call the google api with our access token to get the data we need
var googlePeopleEndpoint = "https://discordapp.com/api/users/@me";
var getRequest = new RestRequest(googlePeopleEndpoint);
getRequest.AddHeader("Authorization", $"Bearer {accessToken}");
var getResponse = await client.ExecuteGetAsync(getRequest);
if (!getResponse.IsSuccessful)
{
//TODO: Maybe add better error handling
Logger.Debug("OAuth2 api access error: " + getResponse.Content!);
return null;
}
// Parse response
var getData = new ConfigurationBuilder().AddJsonStream(
new MemoryStream(Encoding.ASCII.GetBytes(getResponse.Content!))
).Build();
return new User()
{
Email = getData.GetValue<string>("email"),
FirstName = "User",
LastName = "User",
DiscordId = getData.GetValue<ulong>("id"),
Status = UserStatus.DataPending
};
}
private string GetBaseUrl()
{
if (EnableOverrideUrl)
return OverrideUrl;
return AppUrl;
}
}

View file

@ -0,0 +1,85 @@
using Moonlight.App.Database.Entities;
using Moonlight.App.Exceptions;
using Moonlight.App.Helpers;
using Moonlight.App.Models.Misc;
using Moonlight.App.OAuth2;
using Moonlight.App.OAuth2.Providers;
namespace Moonlight.App.Services;
public class OAuth2Service
{
public readonly Dictionary<string, OAuth2Provider> Providers = new();
private readonly OAuth2ProviderConfig[] Configs;
private readonly ConfigService ConfigService;
private readonly IServiceScopeFactory ServiceScopeFactory;
private readonly string OverrideUrl;
private readonly bool EnableOverrideUrl;
private readonly string AppUrl;
public OAuth2Service(ConfigService configService, IServiceScopeFactory serviceScopeFactory)
{
ConfigService = configService;
ServiceScopeFactory = serviceScopeFactory;
var config = ConfigService.GetSection("Moonlight").GetSection("OAuth2");
Configs = config.GetSection("Providers").Get<OAuth2ProviderConfig[]>();
OverrideUrl = config.GetValue<string>("OverrideUrl");
EnableOverrideUrl = config.GetValue<bool>("EnableOverrideUrl");
AppUrl = configService.GetSection("Moonlight").GetValue<string>("AppUrl");
// Register additional providers here
RegisterOAuth2<DiscordOAuth2Provider>("discord");
RegisterOAuth2<GoogleOAuth2Provider>("google");
}
private void RegisterOAuth2<T>(string id, string displayName = "")
{
var name =
string.IsNullOrEmpty(displayName) ?
StringHelper.CapitalizeFirstCharacter(id) : displayName;
var provider = Activator.CreateInstance<T>()! as OAuth2Provider;
if (provider == null)
throw new Exception($"Unable to cast oauth2 provider '{typeof(T).Name}'");
provider.Config = Configs.First(x => x.Id == id);
provider.Url = GetAppUrl();
provider.ServiceScopeFactory = ServiceScopeFactory;
provider.DisplayName = name;
Providers.Add(id, provider);
}
public async Task<string> GetUrl(string id)
{
if (Providers.All(x => x.Key != id))
throw new DisplayException("Invalid oauth2 id");
var provider = Providers[id];
return await provider.GetUrl();
}
public async Task<User> HandleCode(string id, string code)
{
if (Providers.All(x => x.Key != id))
throw new DisplayException("Invalid oauth2 id");
var provider = Providers[id];
return await provider.HandleCode(code);
}
private string GetAppUrl()
{
if (EnableOverrideUrl)
return OverrideUrl;
return AppUrl;
}
}

View file

@ -23,7 +23,6 @@ using Moonlight.App.Services.LogServices;
using Moonlight.App.Services.Mail;
using Moonlight.App.Services.Minecraft;
using Moonlight.App.Services.Notifications;
using Moonlight.App.Services.OAuth2;
using Moonlight.App.Services.Sessions;
using Moonlight.App.Services.Statistics;
using Moonlight.App.Services.SupportChat;
@ -119,9 +118,7 @@ namespace Moonlight
builder.Services.AddScoped<RatingService>();
builder.Services.AddScoped<ReCaptchaService>();
builder.Services.AddScoped<IpBanService>();
builder.Services.AddScoped<GoogleOAuth2Service>();
builder.Services.AddScoped<DiscordOAuth2Service>();
builder.Services.AddSingleton<OAuth2Service>();
builder.Services.AddScoped<SubscriptionService>();
builder.Services.AddScoped<SubscriptionAdminService>();

View file

@ -11,7 +11,6 @@
@using Logging.Net
@using Moonlight.App.Database.Entities
@using Moonlight.App.Models.Misc
@using Moonlight.App.Services.OAuth2
@using Moonlight.App.Services.Sessions
@using System.ComponentModel.DataAnnotations
@using Moonlight.App.Models.Forms
@ -21,8 +20,7 @@
@inject SmartTranslateService SmartTranslateService
@inject CookieService CookieService
@inject NavigationManager NavigationManager
@inject GoogleOAuth2Service GoogleOAuth2Service
@inject DiscordOAuth2Service DiscordOAuth2Service
@inject OAuth2Service OAuth2Service
<div class="d-flex flex-center">
<div class="card rounded-3 w-md-550px">
@ -39,25 +37,23 @@
<TL>Sign in to start with moonlight</TL>
</div>
</div>
<div class="row g-3 mb-9">
<div class="col-md-6">
<a href="#" @onclick:preventDefault @onclick="DoDiscord" class="btn btn-flex btn-outline btn-text-gray-700 btn-active-color-primary bg-state-light flex-center text-nowrap w-100">
<div class="h-15px me-3">
<i class="mb-1 bx bx-md bxl-discord-alt"></i>
@foreach (var providers in OAuth2Service.Providers.Chunk(2))
{
<div class="row g-3 mb-9">
@foreach (var provider in providers)
{
<div class="col">
<a href="#" @onclick:preventDefault @onclick="() => StartOAuth2(provider.Key)" class="btn btn-flex btn-outline btn-text-gray-700 btn-active-color-primary bg-state-light flex-center text-nowrap w-100">
<div class="h-15px me-3">
<i class="mb-1 bx bx-md bx-fingerprint"></i>
</div>
<TL>Sign in with</TL>&nbsp; @(provider.Value.DisplayName)
</a>
</div>
<TL>Sign in with Discord</TL>
</a>
}
</div>
<div class="col-md-6">
<a href="#" @onclick:preventDefault @onclick="DoGoogle" class="btn btn-flex btn-outline btn-text-gray-700 btn-active-color-primary bg-state-light flex-center text-nowrap w-100">
<div class="h-15px me-3">
<i class="mb-1 bx bx-md bxl-google"></i>
</div>
<TL>Sign in with Google</TL>
</a>
</div>
</div>
}
<div class="separator separator-content my-14">
<span class="w-125px text-gray-500 fw-semibold fs-7">
@ -171,6 +167,9 @@
}
catch (Exception e)
{
Logger.Error("Error while login");
Logger.Error(e);
// Reset state
LoginData = new();
TotpData = new();
@ -180,21 +179,12 @@
SmartTranslateService.Translate("Error"),
SmartTranslateService.Translate("An error occured while logging you in")
);
Logger.Error("Error while login");
Logger.Error(e);
}
}
private async Task DoGoogle()
private async Task StartOAuth2(string id)
{
var url = await GoogleOAuth2Service.GetUrl();
NavigationManager.NavigateTo(url, true);
}
private async Task DoDiscord()
{
var url = await DiscordOAuth2Service.GetUrl();
NavigationManager.NavigateTo(url, true);
var url = await OAuth2Service.GetUrl(id);
NavigationManager.NavigateTo(url ,true);
}
}

View file

@ -6,18 +6,16 @@
*@
@using Moonlight.App.Services
@using Moonlight.App.Services.OAuth2
@using Moonlight.App.Models.Forms
@using Moonlight.App.Services.Interop
@using Moonlight.App.Services.Sessions
@inject SmartTranslateService SmartTranslateService
@inject GoogleOAuth2Service GoogleOAuth2Service
@inject NavigationManager NavigationManager
@inject DiscordOAuth2Service DiscordOAuth2Service
@inject AlertService AlertService
@inject UserService UserService
@inject CookieService CookieService
@inject OAuth2Service OAuth2Service
<div class="d-flex flex-center">
<div class="card rounded-3 w-md-550px">
@ -33,24 +31,22 @@
</div>
</div>
<div class="row g-3 mb-9">
<div class="col-md-6">
<a href="#" @onclick:preventDefault @onclick="DoDiscord" class="btn btn-flex btn-outline btn-text-gray-700 btn-active-color-primary bg-state-light flex-center text-nowrap w-100">
<div class="h-15px me-3">
<i class="mb-1 bx bx-md bxl-discord-alt"></i>
@foreach (var providers in OAuth2Service.Providers.Chunk(2))
{
<div class="row g-3 mb-9">
@foreach (var provider in providers)
{
<div class="col-md-6">
<a href="#" @onclick:preventDefault @onclick="() => StartOAuth2(provider.Key)" class="btn btn-flex btn-outline btn-text-gray-700 btn-active-color-primary bg-state-light flex-center text-nowrap w-100">
<div class="h-15px me-3">
<i class="mb-1 bx bx-md bx-fingerprint"></i>
</div>
<TL>Sign in with</TL> @(provider.Value.DisplayName)
</a>
</div>
<TL>Sign up with Discord</TL>
</a>
}
</div>
<div class="col-md-6">
<a href="#" @onclick:preventDefault @onclick="DoGoogle" class="btn btn-flex btn-outline btn-text-gray-700 btn-active-color-primary bg-state-light flex-center text-nowrap w-100">
<div class="h-15px me-3">
<i class="mb-1 bx bx-md bxl-google"></i>
</div>
<TL>Sign up with Google</TL>
</a>
</div>
</div>
}
<div class="separator separator-content my-10">
<span class="w-125px text-gray-500 fw-semibold fs-7">
@ -112,16 +108,10 @@
{
private UserRegisterModel UserRegisterModel = new();
private async Task DoGoogle()
private async Task StartOAuth2(string id)
{
var url = await GoogleOAuth2Service.GetUrl();
NavigationManager.NavigateTo(url, true);
}
private async Task DoDiscord()
{
var url = await DiscordOAuth2Service.GetUrl();
NavigationManager.NavigateTo(url, true);
var url = await OAuth2Service.GetUrl(id);
NavigationManager.NavigateTo(url ,true);
}
private async Task CreateUser()

View file

@ -34,17 +34,20 @@
"Website": "https://mycoolproject.de/"
},
"OAuth2": {
"Discord": {
"ClientId": "10324",
"ClientSecret": "s3cr3t",
"Enable": "True"
},
"Google": {
"ClientId": "xyz.apps.googleusercontent.com",
"ClientSecret": "s3cr3t",
"Enable": "True"
},
"EnableOverrideUrl": "True",
"_exampleProviders": [
{
"Id": "discord",
"ClientId": "",
"ClientSecret": ""
},
{
"Id": "google",
"ClientId": "",
"ClientSecret": ""
}
],
"Providers": [],
"EnableOverrideUrl": false,
"OverrideUrl": "http://your-moonlight-url.test"
},
"Security": {