رامین اسلامی

ورود با گوگل به وب سایتهای ساخته شده با blazor

روش ساخت ورود با گوگل در Blazor Auto Server  در این آموزش نحوه ایجاد کردن ورود با گوگل بدون entityframework (ef) را به همراه کدهای لازم شرح میدهم. این آموزش در بستر Asp.net Blazor Auto ایجاد گردیده و برای Blazor Server هم صادق می باشد.

ورود با گوگل به وب سایتهای ساخته شده با blazor - مدرسه آنلاین دورآموز

روش ساخت ورود با گوگل در Blazor Auto Server 

در این آموزش نحوه ایجاد کردن ورود با گوگل بدون entityframework (ef) را به همراه کدهای لازم شرح میدهم.

این آموزش در بستر Asp.net Blazor Auto ایجاد گردیده و برای Blazor Server هم صادق می باشد.

مراحل ورود با گوگل در وب سایت های blazor به شرح زیر می باشد

  •  ابتدا در  کنسول گوگل یک نام برای برنامه خود ایجاد و یک clientId , secret key دریافت کنید
  • یک پروژه  Blazor Auto server ایجاد کنید که ما در این مثال از core .net 9 استفاده نموده ایم
  • ناگت های زیر را نصب نمایید

 

<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.10" />
    
  • فایل program.cs را به صورت زیر تغییر دهید
using GoogleAuthArian.Components;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Google;


var builder = WebApplication.CreateBuilder(args);

// Add services
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents()
    .AddInteractiveWebAssemblyComponents();

// اضافه شود
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
    options.LoginPath = "/login";
    options.LogoutPath = "/logout";
    options.ExpireTimeSpan = TimeSpan.FromDays(30);
})
.AddGoogle(options =>
{
    options.ClientId = builder.Configuration["Authentication:Google:ClientId"];
    options.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
    options.CallbackPath = "/signin-google";
    options.SaveTokens = true;

    // Request the correct scopes for profile information
    options.Scope.Add("https://www.googleapis.com/auth/userinfo.profile");
    options.Scope.Add("https://www.googleapis.com/auth/userinfo.email");

    // Map the claims properly
    options.ClaimActions.MapJsonKey("picture", "picture");
    options.ClaimActions.MapJsonKey("email", "email");
    options.ClaimActions.MapJsonKey("name", "name");
    options.ClaimActions.MapJsonKey("given_name", "given_name");
    options.ClaimActions.MapJsonKey("family_name", "family_name");
});

builder.Services.AddAuthorization();
builder.Services.AddCascadingAuthenticationState();


var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseWebAssemblyDebugging();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAntiforgery();

// اضافه شود
app.UseAuthentication();
app.UseAuthorization();

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode()
    .AddInteractiveWebAssemblyRenderMode();

// اضافه شود
app.MapGet("/login", async (HttpContext context, string returnUrl = "/") =>
{
    await context.ChallengeAsync(GoogleDefaults.AuthenticationScheme, new()
    {
        RedirectUri = returnUrl
    });
});

app.MapPost("/logout", async (HttpContext context) =>
{
    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

    // پاک کردن همه کوکی‌های احراز هویت
    var cookiesToDelete = new[] {
        "MyApp.Auth",
        ".AspNetCore.Cookies",
        ".AspNetCore.Identity.Application"
    };

    foreach (var cookieName in cookiesToDelete)
    {
        context.Response.Cookies.Delete(cookieName);
        context.Response.Cookies.Append(cookieName, "", new CookieOptions
        {
            Expires = DateTimeOffset.Now.AddDays(-1),
            Path = "/"
        });
    }

    // هدرهای ضد کش
    context.Response.Headers["Cache-Control"] = "no-cache, no-store, must-revalidate";
    context.Response.Headers["Pragma"] = "no-cache";
    context.Response.Headers["Expires"] = "0";

    return Results.Redirect("/");
});
app.Run();
  • در فایل appsettings.json کدهای زیر را اضافه کنید
  "Authentication": {
    "Google": {
      "ClientId": " کلایت ای دی.apps.googleusercontent.com",
      "ClientSecret": "کلاینت سکرت"
    }

6-فایل MainLauout.razor را به صورت زیر تغییر دهید

@using Microsoft.AspNetCore.Components.Authorization
@using System.Security.Claims
@inherits LayoutComponentBase

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <main>
        <div class="top-row px-4">
            <AuthorizeView>
                <Authorized>
                    @if (HasProfilePicture)
                    {
                        <img src="@ProfilePictureUrl"
                             alt="Profile"
                             class="rounded-circle me-2"
                             style="width: 38px; height: 38px; object-fit: cover; border: 2px solid #fff; cursor: pointer;" />

                    }
                    else
                    {
                        <div class="rounded-circle bg-light d-inline-flex align-items-center justify-content-center me-2"
                             style="width: 38px; height: 38px; border: 2px solid #fff; cursor: pointer;">
                            <i class="bi bi-person-fill text-primary"></i>
                        </div>

                    }

                    <span class=" me-3">Hello, @UserName!</span>
                    <form method="post" action="/logout">
                        <button type="submit" class="btn btn-outline-danger btn-sm">
                            <i class="bi bi-box-arrow-right"></i> Logout
                        </button>
                    </form>
                    <a href="/user-profile" class="btn btn-warning">profile</a>
                </Authorized>
                <NotAuthorized>
                    <a href="/login" class="btn btn-primary btn-sm">
                        <i class="bi bi-google"></i> Sign in with Google
                    </a>
                </NotAuthorized>
            </AuthorizeView>

        </div>

        <article class="content px-4">
            @Body
        </article>
    </main>
</div>

<div id="blazor-error-ui" data-nosnippet>
    An unhandled error has occurred.
    <a href="." class="reload">Reload</a>
    <span class="dismiss">🗙</span>
</div>
@code {
[CascadingParameter]
    private Task<AuthenticationState>? AuthenticationStateTask { get; set; }

    private string UserName { get; set; } = "User";
    private string ProfilePictureUrl { get; set; } = string.Empty;
    private bool HasProfilePicture => !string.IsNullOrEmpty(ProfilePictureUrl);
    

    protected override async Task OnInitializedAsync()
    {
        await LoadUserInfo();
    }

    private async Task LoadUserInfo()
    {
        if (AuthenticationStateTask != null)
        {
            var authState = await AuthenticationStateTask;
            var user = authState.User;

            if (user.Identity?.IsAuthenticated == true)
            {
                // Try different claim types for profile picture
                ProfilePictureUrl =
                    user.FindFirst("picture")?.Value ??
                    user.FindFirst("image")?.Value ??
                    user.FindFirst("avatar")?.Value ??
                    user.FindFirst("photo")?.Value ??
                    user.FindFirst("profile")?.Value ??
                    string.Empty;

                UserName = user.FindFirst(ClaimTypes.Name)?.Value ??
                          user.FindFirst("name")?.Value ??
                          "User";

                
                StateHasChanged();

                
            }
        }
    }
}
  • یک صفحه به نام UserProfile.razor درون پوشه Pages ایجاد کرده و کدهای زیر را درون آن قرار دهید
@page "/user-profile"
@attribute [Microsoft.AspNetCore.Authorization.Authorize]
@using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization

<PageTitle>My Profile</PageTitle>

<div class="container mt-4">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="d-flex justify-content-between align-items-center mb-4">
                <h1>My Profile</h1>
                <a href="/" class="btn btn-outline-secondary">
                    <i class="bi bi-arrow-left"></i> Back to Home
                </a>
            </div>

            <AuthorizeView>
                <Authorized>
                    <div class="card">
                        <div class="card-header bg-primary text-white">
                            <h4 class="mb-0">
                                <i class="bi bi-person-circle me-2"></i>
                                Profile Information
                            </h4>
                        </div>
                        <div class="card-body">
                            <div class="row">
                                <!-- Profile Picture Section -->
                                <div class="col-md-4 text-center">
                                    @if (!string.IsNullOrEmpty(ProfilePicture))
                                    {
                                        <img src="@ProfilePicture"
                                             alt="Profile"
                                             class="rounded-circle mb-3 profile-picture-large"
                                             style="width: 150px; height: 150px; object-fit: cover; border: 4px solid #007bff; cursor: pointer;"
                                             onclick="this.style.transform = this.style.transform === 'scale(1.2)' ? 'scale(1)' : 'scale(1.2)';"
                                             title="Click to zoom" />
                                    }
                                    else
                                    {
                                        <div class="rounded-circle bg-secondary d-inline-flex align-items-center justify-content-center mb-3"
                                             style="width: 150px; height: 150px; border: 4px solid #007bff;">
                                            <i class="bi bi-person-fill text-white" style="font-size: 4rem;"></i>
                                        </div>
                                    }
                                    <div>
                                        <button class="btn btn-outline-primary btn-sm mt-2" @onclick="RefreshProfile">
                                            <i class="bi bi-arrow-clockwise"></i> Refresh
                                        </button>
                                    </div>
                                </div>

                                <!-- User Details Section -->
                                <div class="col-md-8">
                                    <div class="row mb-3">
                                        <div class="col-sm-4"><strong>Full Name:</strong></div>
                                        <div class="col-sm-8">@UserName</div>
                                    </div>
                                    <div class="row mb-3">
                                        <div class="col-sm-4"><strong>Email:</strong></div>
                                        <div class="col-sm-8">
                                            <a href="mailto:@UserEmail" class="text-decoration-none">@UserEmail</a>
                                        </div>
                                    </div>
                                    <div class="row mb-3">
                                        <div class="col-sm-4"><strong>Authentication:</strong></div>
                                        <div class="col-sm-8">
                                            <span class="badge bg-success">Google</span>
                                        </div>
                                    </div>
                                    <div class="row mb-3">
                                        <div class="col-sm-4"><strong>Account Created:</strong></div>
                                        <div class="col-sm-8">@AccountCreated.ToString("MMMM dd, yyyy")</div>
                                    </div>
                                    <div class="row mb-3">
                                        <div class="col-sm-4"><strong>Last Login:</strong></div>
                                        <div class="col-sm-8">@LastLogin.ToString("MMMM dd, yyyy 'at' hh:mm tt")</div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

                    <!-- Additional Info Card -->
                    <div class="card mt-4">
                        <div class="card-header">
                            <h5 class="mb-0">
                                <i class="bi bi-info-circle me-2"></i>
                                Account Details
                            </h5>
                        </div>
                        <div class="card-body">
                            <div class="row">
                                <div class="col-md-6">
                                    <h6>Authentication Claims</h6>
                                    <div style="max-height: 200px; overflow-y: auto;">
                                        @if (currentUser?.Claims != null)
                                        {
                                            @foreach (var claim in currentUser.Claims.Take(10))
                                            {
                                                <div class="mb-1">
                                                    <small>
                                                        <strong>@claim.Type:</strong>
                                                        <span class="text-muted">@(claim.Value.Length > 50 ? claim.Value.Substring(0, 50) + "..." : claim.Value)</span>
                                                    </small>
                                                </div>
                                            }
                                        }
                                    </div>
                                </div>
                                <div class="col-md-6">
                                    <h6>Quick Actions</h6>
                                    <div class="d-grid gap-2">
                                        <form method="post" action="/logout">
                                            <button type="submit"  class="btn btn-outline-danger btn-sm">
                                            <i class="bi bi-box-arrow-right"></i> Logout
                                        </button>
                                        </form>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </Authorized>
            </AuthorizeView>
        </div>
    </div>
</div>

@code {
    private string UserName { get; set; } = string.Empty;
    private string UserEmail { get; set; } = string.Empty;
    private string ProfilePicture { get; set; } = string.Empty;
    private ClaimsPrincipal? currentUser;
    private DateTime AccountCreated { get; set; } = DateTime.Now;
    private DateTime LastLogin { get; set; } = DateTime.Now;

    [CascadingParameter]
    private Task<AuthenticationState>? AuthenticationStateTask { get; set; }

    protected override async Task OnInitializedAsync()
    {
        await LoadUserData();
    }

    private async Task LoadUserData()
    {

        if (AuthenticationStateTask != null)
        {
            var authState = await AuthenticationStateTask;
            currentUser = authState.User;

            if (currentUser?.Identity?.IsAuthenticated == true)
            {
                UserName = currentUser.FindFirst(ClaimTypes.Name)?.Value ??
                          currentUser.FindFirst("name")?.Value ?? "Unknown User";
                UserEmail = currentUser.FindFirst(ClaimTypes.Email)?.Value ?? "No email provided";
                ProfilePicture = currentUser.FindFirst("picture")?.Value ?? string.Empty;

                // Set login timestamps (in a real app, you'd get these from your database)
                LastLogin = DateTime.Now;
            }
        }
    }

    private async Task RefreshProfile()
    {
        await LoadUserData();
        StateHasChanged();
    }

}

 

پایان

 


رامین اسلامی-مدرسه آنلاین دورآموز

رامین اسلامی

مدیر وب سایت دورآموز ، تیم برنامه نویسی جی وب و امور مشترکین مخابرات . برنامه نویس و مدرس زبان های برنامه نویسی و گرافیک سازمان فنی و حرفه ای

به نام خدا

رامین اسلامی هستم ، مدیر وب سایت دورآموز ،مدیر پروژه تیم جی وب ، برنامه نویس هریس کامپیوتر شعبه کانادا و برنامه نویس و مدرس زبان های برنامه نویسی .

من  یک توسعه‌دهنده نرم‌افزار و از علاقمندان فن‌آوری‌های مایکروسافت هستم و دوست دارم روی آنها کار کنم. حوزه اصلی تمرکز من روی C#.Net، Asp.Net، Sqlserver، Entity Framework، MVC، Web API، Jquery و Maui می باشد

  •  ProductRaes@Gmail.com
  •  09155143391

 

بیش از 7 سال سابقه در مدیریت پروژه سیستم طرح جامع امور مشترکین مخابرات استان خراسان رضوی ، 4 سال مدیریت تیم برنامه نویسی شبکه سبز ، 7 سال مدیر وبسایت دورآموز و 20 سال سابقه آموزش در آموزشگاه های مشهد و تهران  را دارا می باشم.

یکی از زیباترین لحظات زندگیم ، آموزش هرآنچه فراگرفته ام و مشاهده پیشرفت شاگردانم می باشد.و باعث سرافراری و خرسندی من می باشد که تعداد زیادی از شاگردان قدیمیم همکاران و رقیبان کاری حال حاضر من می باشند.

سابقه برنامه نویسی من

بیش از 7 سال سابقه در مدیریت پروژه سیستم طرح جامع امور مشترکین مخابرات استان خراسان رضوی شامل بخش های :امورمشترکین , ام دی اف , سالن دستگاه , رئیس مرکز , واگذاری خطوط , آبونمان - مدیر پروژه تیم برنامه نویسی جی وب -  سیستم pap مخابرات -  سیستم اداره ترابری مخابرات -  سیستم حسابداری پویا - ویندوز جادویی پویا - سیستم  سهام شرکت تعاونی آتیه شرق - مدیریت فروش سوپرگوشت  - سایت فروش آسان تست - ۱۰ مجموعه تست و آموزش تصویری آسان تست - خودآزمون  حسابداری  - خودآزمون دیپلم کامپیوتر  -  وبسایت آموزشگاه کامپیوتر پژوهش  - وبسایت آزمون های بین المللی ICDL پاسارگاد  - وب سایت فرش ستاره کویر یزد  -  سیستم حسابداری گل فروشی ایمانا  -  سایت رسمی شرکت پیمانکاری peykavan مالزی  -  انجمن داروخانه های خراسان  - سیستم کنترل تولید شرکت پارس اورتوپد  - فروشگاه اینترنتی قاصتک  - سامانه  فروش بلیط هواپیما مسترتیکو  - پنل مدیریت (CMS) asp.net core  -  باربری حجت بار  و …

سابقه تدریس من

بیش از ۲۰ سال تدرس زبان های برنامه نویسی و گرافیکی و بانک های اطلاعاتی  ,  آموزش کارکنان شرکت گاز مشهد ,  آموزش کارکنان شرکت گاز سرخس ,  آموزش کارکنان اداره مخابرات , آموزش در اموزشگاه های معتبر خراسان رضوی نظیر پاسارگاد ، آراد ، پژوهش ، سنا ، کاسپین و … آموزشگاه رهرو - تهران

فعالیت های من

برگزاری دوره های تخصصی برنامه نویسی در دفتر تیم برنامه نویسی جی وب در شهر مشهد , مشاوره در طراحی بانک های اطلاعاتی , مشاوره و مدیریت پروژه های برنامه نویسی , برنامه نویسی برنامه های کاربردی , برنامه نویسی وب سایت , برنامه نویسی موبایل

 

  • productraes@gmail.com
  • 09155143391
پرسش و پاسخ
نوشته های دیگر این نویسنده

عضوی از دورآموز شو

درخواست مشاوره رایگان می باشد . فقط کافیست شماره همراه خود را ثبت نمایید تا با شما تماس بگیریم

و یا می توانید هم اکنون با شماره 09155143391تماس حاصل نمایید

دورآموزی
شو