Convert to Blazor (#6)

Convert existing progress to Blazor on client and server
This commit was merged in pull request #6.
This commit is contained in:
2020-12-18 21:46:28 -05:00
committed by GitHub
parent 2f84821d11
commit e0b3fa8759
97 changed files with 2592 additions and 31063 deletions

View File

@@ -0,0 +1,112 @@
using JobsJobsJobs.Server.Models;
using JobsJobsJobs.Shared;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace JobsJobsJobs.Server
{
/// <summary>
/// Authentication / authorization utility methods
/// </summary>
public static class Auth
{
/// <summary>
/// Verify the authorization code with Mastodon and get the user's profile
/// </summary>
/// <param name="authCode">The code from the authorization flow</param>
/// <param name="config">The authorization configuration section</param>
/// <returns>The Mastodon account (or an error if one is encountered)</returns>
public static async Task<Result<MastodonAccount>> VerifyWithMastodon(string authCode,
IConfigurationSection config)
{
using var http = new HttpClient();
// Use authorization code to get an access token from NAS
using var codeResult = await http.PostAsJsonAsync("https://noagendasocial.com/oauth/token", new
{
client_id = config["ClientId"],
client_secret = config["Secret"],
redirect_uri = "https://localhost:3005/citizen/authorized",
grant_type = "authorization_code",
code = authCode,
scope = "read"
});
if (!codeResult.IsSuccessStatusCode)
{
Console.WriteLine($"ERR: {await codeResult.Content.ReadAsStringAsync()}");
return Result<MastodonAccount>.AsError(
$"Could not get token ({codeResult.StatusCode:D}: {codeResult.ReasonPhrase})");
}
using var tokenResponse = JsonSerializer.Deserialize<JsonDocument>(
new ReadOnlySpan<byte>(await codeResult.Content.ReadAsByteArrayAsync()));
if (tokenResponse == null)
{
return Result<MastodonAccount>.AsError("Could not parse authorization code result");
}
var accessToken = tokenResponse.RootElement.GetProperty("access_token").GetString();
// Use access token to get profile from NAS
using var req = new HttpRequestMessage(HttpMethod.Get, $"{config["ApiUrl"]}accounts/verify_credentials");
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
using var profileResult = await http.SendAsync(req);
if (!profileResult.IsSuccessStatusCode)
{
return Result<MastodonAccount>.AsError(
$"Could not get profile ({profileResult.StatusCode:D}: {profileResult.ReasonPhrase})");
}
var profileResponse = JsonSerializer.Deserialize<MastodonAccount>(
new ReadOnlySpan<byte>(await profileResult.Content.ReadAsByteArrayAsync()));
if (profileResponse == null)
{
return Result<MastodonAccount>.AsError("Could not parse profile result");
}
if (profileResponse.Username != profileResponse.AccountName)
{
return Result<MastodonAccount>.AsError(
$"Profiles must be from noagendasocial.com; yours is {profileResponse.AccountName}");
}
return Result<MastodonAccount>.AsOk(profileResponse);
}
/// <summary>
/// Create a JSON Web Token for this citizen to use for further requests to this API
/// </summary>
/// <param name="citizen">The citizen for which the token should be generated</param>
/// <param name="config">The authorization configuration section</param>
/// <returns>The JWT</returns>
public static string CreateJwt(Citizen citizen, IConfigurationSection config)
{
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.NameIdentifier, citizen.Id.ToString()),
new Claim(ClaimTypes.Name, citizen.DisplayName),
}),
Expires = DateTime.UtcNow.AddHours(2),
Issuer = "https://jobsjobs.jobs",
Audience = "https://jobsjobs.jobs",
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["ServerSecret"])),
SecurityAlgorithms.HmacSha256Signature)
});
return tokenHandler.WriteToken(token);
}
}
}