# إضافة قوقل أوت بدون ASP.NET قاعدة بيانات الهوية

<!--category-- ASP.NET, Google Auth -->
<datetime class="hidden">2024-08-05T08:06</datetime>

## المقدمة

في هذا التطبيق أردت أن أضيف ميكانيكية نموذجية تسمح بالدخول لإضافة تعليقات (و بعض المهام الإدارية) إلى التطبيقM SK2 أردت استخدام قوقل أوث لهذا الهدفMSC3 لم أكن أريد استخدام قاعدة البيانات الرمزية للإنترنت . ل purpose NET Identity

البيانات هي جزء قوي من أي تطبيق لكنها أيضاً تضيف تعقيداً

[TOC]

## الخطوات

أولاً تحتاج لإعداد قوقل أوث في واجهة جوجل المطورين. يمكنك أن تتبع الخطوات في هذا [الروابط](https://developers.google.com/identity/gsi/web/guides/overview) لتحصل على إعداد معلوماتك لـ Google Client ID و Secret.

بمجرد حصولك على رقم مشتري غوغل الخاص بك و السرية , يمكنك إضافةها لإعدادات التطبيق . ឯកសារ جيسون

```json
    "Auth" :{
"GoogleClientId": "",
"GoogleClientSecret": ""
}
```

على الرغم من أنكم لا يجب أن تcheckوا هذه في تحكم المصدر. بدلاً عن التطوير المحلي يمكنكم استخدام ملف السرات:

![secrets.png](secrets.png)

هناك يمكنك أن تضيف رقم هاتفك الشخصي جوجل و السري (لاحظ أن رقم هاتفكم الشخصي هو ' ليس في الواقع مخفياً | , | كما ترون لاحقاً

```json
    "Auth" :{
  "GoogleClientId": "ID",
  "GoogleClientSecret": "CLIENTSECRET"
}
```

## Konfiguration of Google Auth with POCO

ملاحظة أنا أستخدم النسخة المعدلة من ستيف سميث
هذا لتجنب أشياء IOptions التي أجدها مشوشة قليلاً ( و نادراً ما أحتاج لأنني لا أغيّر أبداً البنية التحتية بعد نشر السيناريوهات الخاصة بي

في خاصتي أفعل هذا الذي يسمح لي بأخذ اسم القسم من الفصل نفسه:

<details>
<summary>Click to expand</summary>

```csharp


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; }
}
```

</details>
إذن فإن عمتي تبدو مثل

```csharp
public class Auth : IConfigSection
{
    public static string Section => "Auth";
    public string GoogleClientId { get; set; }
    public string GoogleClientSecret { get; set; }
    
    public string AdminUserGoogleId { get; set; }
    
}
```

حيث أستخدم طريقة واجهة ثابتة للحصول على اسم القسم.

ثم في البداية يمكنني القيام بهذا:

```csharp
var auth = builder.GetConfig<Auth>();
```

على أي حال بالعودة إلى أشياء جوجل!

## الإعداد للبرنامج.cs

لإضافة هذا في الواقع

```csharp
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;
    });
```

سوف تلاحظون هنا .. ان مدخلات "كورس" في "مسك 1" هنا .. وان مدخلة "مسكو 2" يجب ان تضعوها ايضاً في واجهة الهوية

![googleidentity.png](googleidentity.png)

هذا يضمن أن Google Auth يمكن استخدامه فقط من المجالات التي تحددها.

## قوقل Auth في Razor

في _التصميم.cshtml لدي هذا Javascript, هذا هو المكان الذي أقوم بإعداد زرات غوغل خاصتي و تنشيط استدعاء والذي يسجل التطبيق ASP

# غوغل جي إس

```html
<script src="https://accounts.google.com/gsi/client" async defer></script>
```

هذا هو المنخفض للبرمجة التالية

```javascript


        
        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;

```

هنا يمكنكم أن تروا أن لدي ما يصل إلى اثنين من عناصر div في الصفحة مع id google_أزرار و google _أمرار2. هذه هي العناصر التي سيحولها غوغل JS الأزرار إلى

نصيحة : إذا كنت تستخدم "Tailwind" , يمكنك أن تضغط على زر "div" لتعمل بشكل صحيح في режим الظلام | | ( | وإلا سيظهر خلفية بيضاء حول الزر |

```html
<div class="w-[200px] h-[39px] overflow-hidden rounded">
    <div id="google_button">
    </div>
</div>
```

في ال JavaScript الأعلى أقوم بنشر هذا مرة أخرى إلى عمل تحكم يدعى Login. هذا هو المكان الذي أتعامل فيه مع Auth قوقل.

```javascript
      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 }));
```

## توظيف قوقل في المتحكم

المتحكم هنا ' إنه ' هو بسيط جداً فقط يأخذ JWT المرسل , يفك شفرة ثم يستخدم ذلك للدخول إلى التطبيق .

```csharp
    [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();
        }
    }
```

ملاحظة : هذا ليس ' ناظف كما أنه يجمع أسماء Claims ( جميعها في الصيغة السفلية ) لكنه يعمل الآن .

### طبقة تحكم أساسية لإستخراج خصائص الدخول

في جهاز التحكم الأساسي أستخرج الخصائص التي أحتاجها

```csharp
      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);
    }
```

و هذا 's it! هذا يسمح لك باستخدام اعتماد غوغل دون استخدام قاعدة بيانات الهوية في ASP