بررسی احراز هویت و سطح دسترسی کاربران یکی از مباحث مورد نیاز در اکثر وب سایت ها و پروژه های تحت وب است. در Blazor هم امکاناتی برای authentication و authorization وجود دارد که در این سری از مقالات با آن ها آشنا خواهیم شد. در این مقاله به بررسی AuthenticationStateProvider در Blazor WebAssembly می پردازیم که قدم اول در احراز هویت در بلیزر است.

همانطور که از نام AuthenticationStateProvider مشخص است، وظیفه دارد وضعیت احراز هویت کاربر را مشخص کند. برای مثال قادر خواهیم بود اگر کاربر احراز هویت نشده باشد (unauthorized) دسترسی به برخی از کامپوننت ها یا اجزای یک کامپوننت نداشته باشد.

برای راحتی کار در زمان آموزش از یک کلاس Fake برای AuthenticationStateProvider استفاده می کنیم تا حالت های مختلف احراز هویت کاربر را بدون نیاز به لاگین کردن و وجود کاربر واقعی بررسی کنیم.

ساخت پروژه Blazor WebAssembly

اگر در ساخت پروژه به راهنمایی لازم دارید به مقاله “ساخت یک پروژه PWA با Blazor” مراجعه کنید. در این مقاله کافی است مراحل مربوط به تیتر “ساخت پروژه Blazor PWA” را انجام بدهید. فقط در آخرین مرحله در صورت عدم نیاز به PWA آن را فعال نکنید. به تصویر زیر دقت کنید:

Create Blazor App

همچنین می توانید سورس کد مربوط به این سری از مقالات را در گیت هاب مشاهده کنید : https://github.com/softamoz/LearnAuthBlazor

توجه داشته باشید که بعد از ایجاد پروژه، Solution شما شامل سه پروژه هست. مواردی که در این مقاله بیان شده تماما در پروژه Client یا همان Blazor WebAssembly انجام می شود. از سایر پروژه ها در قسمت های بعدی استفاده خواهد شد.

نصب و راه اندازی پکیج های لازم در پروژه Blazor WebAssembly

بعد از ساخت پروژه باید پکیج Microsoft.AspNetCore.Components.WebAssembly.Authentication از Nuget را در پروژه کلاینت (Blazor WebAssembly) نصب کنید.

سپس در فایل Program.cs همان پروژه با استفاده از دستور زیر، سرویس احراز هویت را در Services رجیستر کنید:

builder.Services.AddAuthorizationCore();

ساخت کلاس AuthenticationStateProvider

برای ساخت یک نمونه Fake از کلاس AuthenticationStateProvider ابتدا پوشه ای با نام AuthProviders ایجاد می کنیم. سپس درون آن کلاسی با نام FakeAuthStateProvider می سازیم و از کلاس AuthenticationStateProvider ارث بری می کنیم. برای این کار باید متد GetAuthenticationStateAsync را override کنیم.

public class FakeAuthStateProvider : AuthenticationStateProvider
    {
        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            await Task.Delay(2000);


            var anonymous = new ClaimsIdentity();   // Anonymous User (UnAuthorized)


            var user = new ClaimsIdentity(new List<Claim>()     //Authenticated User
            {
                new Claim(ClaimTypes.Name,"John Doe"),
                new Claim(ClaimTypes.Role,"Admin")

            }, "Test And Fake");


            return await Task.FromResult(new AuthenticationState(new ClaimsPrincipal(anonymous)));
        }
    }

با نمونه سازی از کلاس ClaimsIdentity دو کاربر ساختیم. یکی با نام anonymous که برای تست به عنوان کاربر احراز هویت نشده مورد استفاده قرار میگیرد و دیگری با نام user که برای تست به عنوان کاربر احراز هویت شده مورد استفاده قرار می گیرد. کافی است در خط آخر (۱۹) این متد هر کدام از انواع کاربر را که برای تست مد نظر داریم، استفاده کنیم.

همچنین در اول متد (خط ۵) از Task.Delay(2000) استفاده کردیم که در ادامه دلیل آن را خواهید فهمید!

حال برای استفاده از این کلاس باید آن را در کلاس Program.cs در Services رجیستر کنیم:

builder.Services.AddScoped<AuthenticationStateProvider, FakeAuthStateProvider>();

اکنون می توانیم از AuthenticationStateProvider استفاده کنیم و آن را در سناریو های مختلف بررسی کنیم.

نحوه استفاده از AuthenticationStateProvider در Blazor

سه حالت زیر برای احراز هویت وجود دارد:

  • Authorized (احراز هویت شده)
  • Not-Authorized (احراز هویت نشده)
  • Authorizing (در حال احراز هویت)

برای استفاده از این حالت ها باید در Routing برنامه تغییر ایجاد کنیم. در فایل App.razor بجای کامپوننت RouteView باید از AuthorizeRouteView استفاده کنیم.

@using Microsoft.AspNetCore.Components.Authorization

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
            <Authorizing>
                <p style="color: darkorange">User Is Authorizing... Please Wait!!!</p>
            </Authorizing>
        </AuthorizeRouteView>
    </Found>
    <NotFound>
        <CascadingAuthenticationState>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
                @*   Or Custom Not Found Component   *@
            </LayoutView>
        </CascadingAuthenticationState>
    </NotFound>
</Router>

برای استفاده از این کامپوننت باید Name Space زیر Using شده باشد:

Microsoft.AspNetCore.Components.Authorization

با استفاده از این کامپوننت به ۳ حالتی که بالاتر ذکر شد، در مورد کاربر جاری دسترسی داریم. همچنین اگر کامپوننت NotFound را شخصی سازی کردیم، میتوانیم در آن از کامپوننت CascadingAuthenticationState برای دسترسی به وضعیت احراز هویت استفاده کنیم.

اگر به خاطر داشته باشید در FakeAuthStateProvider از Task.Delay(2000) استفاده کردیم. با اجرای برنامه ۲ ثانیه طول می کشد تا وضعیت کاربر دریافت شود. در این مدت وضعیت احراز هویت کاربر از نوع Authorizing خواهد بود.

Authorizing State In Blazor

همچنین در کامپوننت AuthorizeRouteView می توانیم از کامپوننت Authorizing برای تغییر پیام این حالت استفاده کنیم. (در صورت عدم استفاده پیام پیشفرض نمایش داده می شود.)

بررسی کامپوننت های Authorized و NotAuthorized

تا اینجا به وضعیت کاربر دسترسی داریم و می توانیم از آن برای نمایش یا عدم نمایش عناصر صفحه به کاربر استفاده کنیم. در Blazor کامپوننتی با عنوان AuthorizeView داریم که می توانیم از دو کامپوننت Authorized و NotAuthorized در آن استفاده کنیم. برای مثال در کامپوننت Index.razor از این کامپوننت ها استفاده می کنیم:

@page "/"

<h1>Hello, world!</h1>
<AuthorizeView>
    <Authorized>
        <p style="color: lime">Authorized User...</p>
    </Authorized>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />
    <NotAuthorized>
        <p style="color: red">Not Authorized User...</p>
    </NotAuthorized>
</AuthorizeView>

همچنین باید Name Space زیر Using شده باشد:

Microsoft.AspNetCore.Components.Authorization

بهتر است این کد را در فایل _Imports.razor قرار دهیم.

برای تست کاربر احراز هویت شده، در کلاس FakeAuthStateProvider از user استفاده کنید و همچنین می توانید برای کاربر احراز هویت نشده از anonymous استفاده کنید. (کاربر لاگین کرده و کاربر لاگین نکرده!)

Authorized User in Blazor

در این کامپوننت از claim ها نیز می توانیم استفاده کنیم. برای مثال :

@page "/"
@using System.Security.Claims

<AuthorizeView Roles="Admin">
    <Authorized>
        <p style="color: lime">Authorized User... Role is : @context.User.FindFirst(ClaimTypes.Role).Value</p>
    </Authorized>

    <NotAuthorized>
        <p style="color: red">Not Authorized User...</p>
    </NotAuthorized>
</AuthorizeView>

شی context حاوی پراپرتی User است که اطلاعات کاربر را در اختیار ما قرار می دهد. (برای اطلاعات بیشتر در مورد ASP .NET Core Identity تحقیق کنید)

برای استفاده از این کد باید Name Space زیر Using شده باشد:

System.Security.Claims

به علاوه کامپوننت AuthorizeView دارای attribute به نام Roles است که می توانیم نمایش آن را برای Role های خاص محدود کنیم:

تا اینجا می توانیم عناصر صفحه را با توجه وضعیت کاربر مدیریت کنیم. ولی آیا این امکان وجود دارد که امکان دسترسی به یک Component را با توجه به وضعیت کاربر کنترل کنیم؟

حفاظت از Component ها با استفاده از AuthenticationStateProvider در Blazor

تا اینجا با استفاده از کامپوننت AuthorizeView می توانیم بر اساس وضعیت کاربر، نمایش یا عدم نمایش عناصر هر کامپوننت را کنترل کنیم. برای مثال در کامپوننت NavMenu.razor تغییراتی ایجاد می کنیم تا کاربران ناشناس نتوانند لینک Fetch Data را ببینند:

.
.
.
<AuthorizeView>
            <Authorized>
                <li class="nav-item px-3">
                    <NavLink class="nav-link" href="fetchdata">
                        <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
                    </NavLink>
                </li>
            </Authorized>
</AuthorizeView>
.
.
.

اگر در کلاس FakeAuthStateProvider از anonymous استفاده کنیم، خواهیم دید لینک Fetch Data نمایش داده نمی شود. اما کامپوننت Fetch Data همچنان از طریق URL در دسترس هست:

برای حل این مشکل کافی است در کامپوننت Fetch Data از کد زیر استفاده کنیم:

@using Microsoft.AspNetCore.Authorization

@attribute [Authorize]

خواهیم دید دسترسی به این کامپوننت حتی از URL برای کاربران Not authorized ممکن نیست.

پیامی که در این حالت نمایش داده می شود، همانند حالت Authorizing که بالاتر ذکر شد قابل ویرایش است. با این تفاوت که باید از کامپوننت NotAuthorized استفاده کنیم. (در فایل App.razor)

دسترسی به Authentication State در کد

در Blazor این امکان وجود دارد که از طریق کد نیز به وضعیت کاربر دسترسی داشته باشیم و بر اساس آن رفتار متفاوتی به کاربر نمایش بدهیم.

کامپوننت Counter را به شکل زیر تغییر می دهیم:

@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    [CascadingParameter]
    public Task<AuthenticationState> UserState { get; set; }

    private async void IncrementCount()
    {
        var authState = await UserState;

        var user = authState.User;

        if (user.Identity.IsAuthenticated)
            currentCount++;
        else
            currentCount--;
    }
}

در این کامپوننت پراپرتی با نام UserState از نوع CascadingParameter اضافه کردیم. در متد IncrementCount با توجه وضعیت کاربر، اگر لاگین کرده باشد مقدار شمارنده یکی اضافه می شود و اگر لاگین نکرده باشد شمارنده کاهش می یابد.

جمع بندی

در این مقاله آموختیم :

  • چگونه از AuthenticationStateProvider در Blazor WebAssembly استفاده کنیم.
  • چگونه بر اساس وضعیت کاربر UI و عملکرد برنامه را کنترل کنیم.
  • با کامپوننت های مربوط به احراز هویت آشنا شدیم.
  • آموختیم چگونه در Code از AuthenticationStateProvider استفاده کنیم.

در مقاله بعدی با نحوه ثبت نام کاربر در Blazor WebAssembly و ASP.NET Core Identity آشنا خواهیم شد. همچنین بجای استفاده از FakeAuthStateProvider ، از یک Provider واقعی استفاده خواهیم کرد. برای یاد گیری احراز هویت در Blazor منتظر مقالات بعدی سافت آموز باشید.

 

منبع : https://code-maze.com/authenticationstateprovider-blazor-webassembly

مطالعه بیشتر در مورد ASP .NET Core Identity در : https://code-maze.com/asp-net-core-identity-series

سورس کد در گیت هاب سافت آموز : https://github.com/softamoz/LearnAuthBlazor