Att lägga till Google Auth utan ASP.NET identitetsdatabas
Inleiding
I den här appen ville jag lägga till en modellmekanism som möjliggör att logga in för att lägga till kommentarer ( och några administratörsuppgifter ) till appen ♫ . ♫ Jag ville använda Google Auth i detta syfte ♫
Databaser är en kraftfull komponent i vilken applikation som helst men de tillsätter också komplexitet.
steg
Först måste du sätta upp Google Auth i Google Developer Console. Du kan följa dessa steg länk för att få dina detaljer ordnade åt dig Google Client ID och Secret.
När du väl har din Google Client ID och Secret, kan du lägga till dem i din appsettings
"Auth" :{
"GoogleClientId": "",
"GoogleClientSecret": ""
}
Hursomhelst borde man inte kolla in dessa i källkodskontrollen. Istället för den lokala utvecklingen kan man använda hemligheterna i filet

Där kan du lägga till din Google Client ID och hemlig. ( lägg märke till att din klient ID inte är identifiserad som ', utan som faktiskt är konfidentiskt.
"Auth" :{
"GoogleClientId": "ID",
"GoogleClientSecret": "CLIENTSECRET"
}
Konfiguration av Google Auth med POCO
Jag använder en modifierad version av Steve Smiths IConfigSection, som nyligen blev berömd av Phil Haack. Detta är för att undvika de IOptionsgrejer som jag finner lite kluriga ( och sällan behöver eftersom jag nästan aldrig ändrar konfiguration efter utplacering i mina scenarios).
I min gör jag detta som tillåter mig att få sektionens namn från klassen själv:
Click to expand
namespace Mostlylucid.Config;
public static class ConfigExtensions {
public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration)
where TConfig : class, new() {
if (services == null) throw new ArgumentNullException(nameof(services));
if (configuration == null) throw new ArgumentNullException(nameof(configuration));
var config = new TConfig();
configuration.Bind(config);
services.AddSingleton(config);
return config;
}
public static TConfig Configure<TConfig>(this WebApplicationBuilder builder)
where TConfig : class, IConfigSection, new() {
var services = builder.Services;
var configuration = builder.Configuration;
var sectionName = TConfig.Section;
return services.ConfigurePOCO<TConfig>(configuration.GetSection(sectionName));
}
public static TConfig GetConfig<TConfig>(this WebApplicationBuilder builder)
where TConfig : class, IConfigSection, new() {
var configuration = builder.Configuration;
var sectionName = TConfig.Section;
var section = configuration.GetSection(sectionName).Get<TConfig>();
return section;
}
public static Dictionary<string, object> GetConfigSection(this IConfiguration configuration, string sectionName) {
var section = configuration.GetSection(sectionName);
var result = new Dictionary<string, object>();
foreach (var child in section.GetChildren()) {
var key = child.Key;
var value = child.Value;
result.Add(key, value);
}
return result;
}
public static Dictionary<string, object> GetConfigSection<TConfig>(this WebApplicationBuilder builder)
where TConfig : class, IConfigSection, new() {
var configuration = builder.Configuration;
var sectionName = TConfig.Section;
return configuration.GetConfigSection(sectionName);
}
}
public interface IConfigSection {
public static abstract string Section { get; }
}
public class Auth : IConfigSection
{
public static string Section => "Auth";
public string GoogleClientId { get; set; }
public string GoogleClientSecret { get; set; }
public string AdminUserGoogleId { get; set; }
}
Där jag använder en statisk gränssnittmetod för att få sektionens namn.
Då kan jag göra det här i min uppstartning.
var auth = builder.GetConfig<Auth>();
Hursomhelst tillbaka till google stuff!
Programm.cs uppsättning
För att faktiskt lägga till detta
services.AddCors(options =>
{
options.AddPolicy("AllowMostlylucid",
builder =>
{
builder.WithOrigins("https://www.mostlylucid.net")
.WithOrigins("https://mostlylucid.net")
.WithOrigins("https://localhost:7240")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services
.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
})
.AddCookie()
.AddGoogle(options =>
{
options.ClientId = auth.GoogleClientId;
options.ClientSecret = auth.GoogleClientSecret;
});
Du kommer att lägga märke till 's CORS-Einträg här, , du behöver också sätta upp dessa i Googles identitetskonsole

Detta gör att Google Auth bara kan användas från domainerna du specifikerar.
Google Auth In Razor
I min _Layout.cshtml Jag har den här Javascript, det är där jag sätter upp mina Google-knappar och utlöser en tillbakalogg som registrerar ASP
Google JS
<script src="https://accounts.google.com/gsi/client" async defer></script>
Det här är dlow för koden som följer:
function renderButton(element)
{
google.accounts.id.renderButton(
element,
{
type: "standard",
size: "large",
width: 200,
theme: "filled_black",
text: "sign_in_with",
shape: "rectangular",
logo_alignment: "left"
}
);
}
function initGoogleSignIn() {
google.accounts.id.initialize({
client_id: "839055275161-u7dqn2oco2729n6i5mk0fe7gap0bmg6g.apps.googleusercontent.com",
callback: handleCredentialResponse
});
const element = document.getElementById('google_button');
if (element) {
renderButton(element);
}
const secondElement = document.getElementById('google_button2');
if (secondElement) {
renderButton(secondElement);
}
}
function handleCredentialResponse(response) {
if (response.credential) {
const xhr = new XMLHttpRequest();
xhr.open('POST', '/login', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function () {
if (xhr.status === 200) {
window.location.reload();
} else {
console.error('Failed to log in.');
}
};
xhr.send(JSON.stringify({ idToken: response.credential }));
} else {
console.error('No credential in response.');
}
}
window.onload = initGoogleSignIn;
Här kan ni se att jag har upp till två div-element i sidan med ID google_knapp och google _knapp
TIP: Om du använder Tailwind , kan du trycka på knappen div för att fungera korrekt i mörk mode ( annars blir det en vit bakgrund kring knappen )
<div class="w-[200px] h-[39px] overflow-hidden rounded">
<div id="google_button">
</div>
</div>
I JavaScript ovanför skriver jag detta tillbaka till en kontrolleraktion som heter Login. Det här är där jag hanterar Google Auth
const xhr = new XMLHttpRequest();
xhr.open('POST', '/login', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function () {
if (xhr.status === 200) {
window.location.reload();
} else {
console.error('Failed to log in.');
}
};
xhr.send(JSON.stringify({ idToken: response.credential }));
Google Auth i kontrollören
Controllern är här.
[Route("login")]
[HttpPost]
public async Task<IActionResult> HandleGoogleCallback([FromBody] GoogleLoginRequest request)
{
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(request.IdToken) as JwtSecurityToken;
if (jsonToken == null)
{
return BadRequest("Invalid token");
}
var claimsIdentity = new ClaimsIdentity(
jsonToken.Claims,
GoogleDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties
{
IsPersistent = true
};
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
authProperties);
return Ok();
}
}
NOTA: Det här är inte ', det är prefekten eftersom det uppfattar påståendets namn. (, de är alla småstämde, ), men det fungerar för tillfället
Controller Base Class för att extrahera inlog properties
I min BaseController extraherar jag de egenskaper som jag behöver;
public record LoginData(bool loggedIn, string? name, string? avatarUrl, string? identifier);
protected LoginData GetUserInfo()
{
var authenticateResult = HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme).Result;
if (authenticateResult.Succeeded)
{
var principal = authenticateResult.Principal;
if(principal == null)
{
return new LoginData(false, null, null, null);
}
var name = principal.FindFirst("name").Value;
var avatarUrl =principal.FindFirst("picture").Value;
var nameIdentifier = principal.FindFirst("sub");
return new LoginData(true, name, avatarUrl, nameIdentifier?.Value);
}
return new LoginData(false,null,null,null);
}
Och det är så.