This article shows how to use MySQL with ASP.NET Core 1.0 using Entity Framework Core.
مسیرراهها
React 16x
پیش نیاز ها
- قسمت 1 : معرفی و شروع به کار
- قسمت 2 : بررسی پیشنیازهای جاوا اسکریپتی - بخش 1
- قسمت 3 : بررسی پیشنیازهای جاوا اسکریپتی - بخش 2
کامپوننت ها
- قسمت 4 : کامپوننتها - بخش 1 - کار با عبارات JSX
- قسمت 5 : کامپوننتها - بخش 2 - نمایش لیستها و مدیریت رویدادها و حالات
- قسمت 6 : کامپوننتها - بخش 3 - یک تمرین
ترکیب کامپوننت ها
- قسمت 7 : ترکیب کامپوننتها - بخش 1 - ارسال دادهها، مدیریت رخدادها
- قسمت 8 : ترکیب کامپوننتها - بخش 2 - مدیریت state
- قسمت 9 : ترکیب کامپوننتها - بخش 3 - Lifecycle Hooks
- قسمت 10 : ترکیب کامپوننتها - بخش 4 - یک تمرین
طراحی یک گرید
- قسمت 11 : طراحی یک گرید - بخش 1 - کامپوننت صفحه بندی
- قسمت 12 : طراحی یک گرید - بخش 2 - فیلتر کردن اطلاعات
- قسمت 13 : طراحی یک گرید - بخش 3 - مرتب سازی اطلاعات
- قسمت 14: طراحی یک گرید - بخش 4 - پویاسازی تعاریف ستونها
مسیریابی
- قسمت 15 :مسیریابی - بخش 1 - تعریف و تنظیم مسیریابیها
- قسمت 16 : مسیریابی - بخش 2 - پارامترهای مسیریابی
- قسمت 17 : مسیریابی - بخش 3 - یک تمرین
کار با فرم ها
- قسمت 18 : کار با فرمها - بخش 1 - دریافت ورودیها از کاربر
- قسمت 19 : کار با فرمها - بخش 2 - اعتبارسنجی ورودیهای کاربران
- قسمت 20 : کار با فرمها - بخش 3 - بهبود کیفیت کدهای فرم لاگین
- قسمت 21 : کار با فرمها - بخش 4 - چند تمرین
ارتباط با سرور
- قسمت 22 : ارتباط با سرور - بخش 1 - برپایی تنظیمات
- قسمت 23 : ارتباط با سرور - بخش 2 - شروع به کار با Axios
- قسمت 24 : ارتباط با سرور - بخش 3 - نکات تکمیلی کار با Axios
- قسمت 25 : ارتباط با سرور - بخش 4 - یک تمرین
احراز هویت و اعتبارسنجی کاربران
- قسمت 26 : احراز هویت و اعتبارسنجی کاربران - بخش 1 - ثبت نام و ورود به سیستم
- قسمت 27 : احراز هویت و اعتبارسنجی کاربران - بخش 2 - استخراج و نمایش اطلاعات JWT و خروج از سیستم
- قسمت 28 : احراز هویت و اعتبارسنجی کاربران - بخش 3 - فراخوانی منابع محافظت شده و مخفی کردن عناصر صفحه
- قسمت 29 : احراز هویت و اعتبارسنجی کاربران - بخش 4 - محافظت از مسیرها
React Hooks
- قسمت 30 : React Hooks - بخش 1 - معرفی useState و useEffect
- قسمت 31 : React Hooks - بخش 2 - مقایسه حالتهای مختلف مدیریت حالت با useState Hook
- قسمت 32 : React Hooks - بخش 3 - نکات ویژهی برقراری ارتباط با سرور
- قسمت 33 : React Hooks - بخش 4 - useContext Hook
توزیع برنامه
مدیریت پیشرفتهی حالت در React با Redux و Mobx
Redux
Redux
- قسمت اول : Redux چیست؟
- قسمت دوم : بررسی توابع Redux
- قسمت سوم : روش اتصال Redux به برنامههای React
- قسمت چهارم : انجام اعمال async با Redux
- قسمت پنجم : Redux Hooks
MobX
- قسمت ششم : MobX چیست؟
- قسمت هفتم : بررسی مفاهیم Mobx
- قسمت هشتم : تنظیمات پروژههای React برای کار با Mobx decorators
- قسمت نهم : مثالی از کتابخانهی mobx-react
- قسمت دهم : MobX Hooks و اعمال Async در Mobx
مطالب تکمیلی
- ساخت یک مثال Todo با MobX و React
- روش یکی کردن پروژههای React و ASP.NET Core
- آپلود فایلها توسط برنامههای React به یک سرور ASP.NET Core به همراه نمایش درصد پیشرفت
- روش کار با فایلهای ایستا در برنامههای React
- روش کار با فایلهای پویای ارائه شدهی توسط یک برنامهی ASP.NET Core در برنامههای React
- استفاده از قالب مخصوص Redux Toolkit جهت ایجاد پروژههای React/Redux
- تبدیل یک قالب HTML معمولی به قالب React
- React component lifecycle
- React reconciliation
در قسمت قبل، کار پیاده سازی سمت سرور نمایش اطلاعات یک گرید، به پایان رسید. در این قسمت میخواهیم از سمت کلاینت، اطلاعات صفحه بندی و مرتب سازی را به سمت سرور ارسال کرده و همچنین نتیجهی دریافتی از سرور را نمایش دهیم.
پیشنیازهای نمایش اطلاعات گرید به همراه صفحه بندی اطلاعات
در مطلب «Angular CLI - قسمت ششم - استفاده از کتابخانههای ثالث» نحوهی نصب و معرفی کتابخانهی ngx-bootstrap را بررسی کردیم. دقیقا همان مراحل، در اینجا نیز باید طی شوند و از این مجموعه تنها به کامپوننت Pagination آن نیاز داریم. همان قسمت ذیل گرید تصویر فوق که شماره صفحات را جهت انتخاب، نمایش دادهاست.
بنابراین ابتدا فرض بر این است که دو بستهی بوت استرپ و ngx-bootstrap را نصب کردهاید:
در فایل angular-cli.json. شیوهنامهی بوت استرپ را نیز افزودهاید:
پس از آن باید بهخاطر داشت که کامپوننت نمایش صفحه بندی این مجموعه PaginationModule نام دارد و باید در نزدیکترین ماژول مورد نیاز، ثبت و معرفی شود:
برای نمونه در این مثال، ماژولی به نام simple-grid.module.ts دربرگیرندهی گرید مطلب جاری است و به صورت ذیل به برنامه اضافه شدهاست:
بنابراین تعریف PaginationModule باید به قسمت imports این ماژول اضافه شود و تعریف آن در app.module.ts تاثیری بر روی این قسمت نخواهد داشت.
کامپوننتی هم که مثال جاری را نمایش میدهد به صورت ذیل به ماژول SimpleGrid فوق اضافه شدهاست:
تهیه معادلهای قراردادهای سمت سرور در سمت Angular
در قسمت قبل، تعدادی قرارداد مانند پارامترهای دریافتی از سمت کلاینت و ساختار اطلاعات ارسالی به سمت کلاینت را تعریف کردیم. اکنون جهت کار strongly typed با آنها در سمت یک برنامهی تایپ اسکریپتی Angular، کلاسهای معادل آنها را تهیه میکنیم.
ساختار شیء محصول دریافتی از سمت سرور
با این محتوا
که در اینجا هر کدام از خواص ذکر شده، معادل camel case نمونهی سمت سرور خود هستند (چون JSON.NET در ASP.NET Core، به صورت پیش فرض یک چنین خروجی را تولید میکند).
ساختار معادل پارامترهای صفحه بندی و مرتب سازی ارسالی به سمت سرور
با این محتوا
در اینجا همان ساختار IPagedQueryModel سمت سرور را مشاهده میکنید. از آن جهت مشخص سازی جزئیات صفحه بندی و نحوهی مرتب سازی اطلاعات، استفاده میشود.
ساختار معادل اطلاعات صفحه بندی شدهی دریافتی از سمت سرور
با این محتوا
این ساختار جنریک نیز دقیقا معادل همان PagedQueryResult سمت سرور است و حاوی تعداد کل ردیفهای یک کوئری و تنها قسمتی از اطلاعات صفحه بندی شدهی آن میباشد.
ساختار ستونهای گرید نمایشی
با این محتوا
هر ستون نمایش داده شده، دارای یک برچسب، خاصیتی مشخص در سمت سرور و بیانگر قابلیت مرتب سازی آن میباشد. اگر isSortable به true تنظیم شود، با کلیک بر روی سرستونها میتوان اطلاعات را بر اساس آن ستون، مرتب سازی کرد.
تهیه سرویس ارسال اطلاعات صفحه بندی به سرور و دریافت اطلاعات از آن
پس از تدارک این مقدمات، اکنون کار تعریف سرویسی که این اطلاعات را به سمت سرور ارسال میکند و نتیجه را باز میگرداند، به صورت ذیل خواهد بود:
این دستور سبب ایجاد کلاس ProductsListService شده و همچنین قسمت providers ماژول simple-grid را نیز بر این اساس به روز رسانی میکند.
پیش از تکمیل این سرویس، نیاز است متدی را جهت تبدیل یک شیء، به معادل کوئری استرینگ آن تهیه کنیم:
در قسمت قبل امضای متد GetPagedProducts دارای ویژگی HttpGet است. بنابراین، نیاز است اطلاعات را به صورت کوئری استرینگ از سمت کلاینت دریافت کند و متد toQueryString فوق به صورت خودکار بر روی تمام خواص یک شیء دلخواه حرکت کرده و آنها را تبدیل به یک رشتهی حاوی کوئری استرینگها میکند.
برای نمونه متد toQueryString فوق است که سبب ارسال یک چنین درخواستی به سمت سرور میشود:
پس از این تعریف، سرویس ProductsListService به صورت ذیل تکمیل خواهد شد:
در اینجا از متد toQueryString، جهت تکمیل متد get ارسالی به سمت سرور استفاده شدهاست تا پارامترها را به صورت کوئری استرینگها تبدیل کرده و ارسال کند.
سپس در متد map آن، res.json دقیقا همان ساختار PagedQueryResult سمت سرور را به همراه دارد. اینجا است که فرصت خواهیم داشت نمونهی سمت کلاینت آنرا که در ابتدای بحث تهیه کردیم، وهله سازی کرده و بازگشت دهیم (نگاشت فیلدهای دریافتی از سمت سرور به سمت کلاینت).
تکمیل کامپوننت نمایش گرید
قسمت آخر این مطلب، استفادهی از این ساختارها و سرویسها و نمایش اطلاعات دریافتی از آنها است. برای این منظور ابتدا نیاز است سرستونهای این گرید را تهیه کرد:
در اینجا ابتدا بررسی میشود که آیا یک ستون قابلیت مرتب سازی را دارد، یا خیر؟ اگر اینطور است، در کنار آن یک گلیف آیکن مرتب سازی درج میشود. اگر خیر، صرفا متن عنوان آن نمایش داده خواهد شد. میشد تمام این موارد را به ازای هر ستون به صورت مجزایی ارائه داد، اما در این حالت به کدهای تکراری زیادی میرسیدیم. به همین جهت از یک حلقه بر روی تعریف ستونهای این گرید استفاده شدهاست. آرایهی این ستونها نیز به صورت ذیل تعریف میشود:
همچنین در کدهای قالب این کامپوننت، مدیریت کلیک بر روی یک سر ستون را نیز مشاهده میکنید:
در اینحالت اگر ستونی که بر روی آن کلیک شده، پیشتر مرتب سازی شدهاست، صرفا خاصیت صعودی بودن آن برعکس خواهد شد. در غیراینصورت، نام خاصیت درخواستی مرتب سازی و جهت آن نیز مشخص میشود. سپس مجددا این گرید توسط متد getPagedProductsList رندر خواهد شد.
کار رندر بدنهی اصلی گرید توسط همین چند سطر در قالب آن مدیریت میشود:
اولین ستون آن، اندکی ابتکاری است. در اینجا شماره ردیفهای خودکاری در هر صفحه درج خواهند شد. این شماره ردیف نیز جزو ستونهای منبع دادهی فرضی برنامه نیست. به همین جهت برای درج آن، توسط let i = index در ngFor، به شماره ایندکس ردیف جاری دسترسی پیدا میکنیم. سپس توسط محاسباتی بر اساس تعداد ردیفهای هر صفحه و شمارهی صفحهی جاری، میتوان شماره ردیف فعلی را محاسبه کرد.
در اینجا حلقهای بر روی queryResult.items تشکیل شدهاست. این منبع داده به صورت ذیل در کامپوننت متناظر مقدار دهی میشود:
ابتدا سرویس ProductsListService را که در ابتدای بحث تکمیل شد، به سازندهی این کامپوننت تزریق میکنیم. به کمک آن میتوان در متد getPagedProductsList، ابتدا queryModel جاری را که شامل اطلاعات مرتب سازی و صفحه بندی است، به سرور ارسال کرده و سپس نتیجهی نهایی را به queryResult انتساب دهیم. به این ترتیب تعداد کل رکوردها و همچنین آیتمهای صفحهی جاری دریافت میشوند. اکنون حلقهی ngFor نمایش بدنهی گرید، کار تکمیل صفحهی جاری را انجام خواهد داد.
قسمت آخر کار، افزودن کامپوننت نمایش شماره صفحات است:
در اینجا از کامپوننت pagination مجموعهی ngx-bootstarp استفاده شدهاست و یک سری از خواص مستند شدهی آن، مقدار دهی شدهاند؛ مانند متنهای صفحهی بعد و قبل و امثال آن. مدیریت کلیک بر روی شمارههای آن، در کامپوننت جاری به صورت ذیل است:
علت تعریف دو خاصیت اضافهی currentPage و numberOfPages، استفادهی از آنها در قسمت ذیل این شمارهها (خارج از کامپوننت نمایش شماره صفحات) جهت نمایش page 1/x است.
هر زمانیکه کاربر بر روی شمارهای کلیک میکند، رخداد onPageChange فراخوانی شده و در اینحالت تنها کافی است شماره صفحهی درخواستی queryModel جاری را به روزرسانی کرده و سپس آنرا در اختیار متد getPagedProductsList جهت دریافت اطلاعات این صفحهی درخواستی قرار دهیم.
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید.
پیشنیازهای نمایش اطلاعات گرید به همراه صفحه بندی اطلاعات
در مطلب «Angular CLI - قسمت ششم - استفاده از کتابخانههای ثالث» نحوهی نصب و معرفی کتابخانهی ngx-bootstrap را بررسی کردیم. دقیقا همان مراحل، در اینجا نیز باید طی شوند و از این مجموعه تنها به کامپوننت Pagination آن نیاز داریم. همان قسمت ذیل گرید تصویر فوق که شماره صفحات را جهت انتخاب، نمایش دادهاست.
بنابراین ابتدا فرض بر این است که دو بستهی بوت استرپ و ngx-bootstrap را نصب کردهاید:
> npm install bootstrap --save > npm install ngx-bootstrap --save
"apps": [ { "styles": [ "../node_modules/bootstrap/dist/css/bootstrap.min.css", "styles.css" ],
import { PaginationModule } from "ngx-bootstrap"; @NgModule({ imports: [ PaginationModule.forRoot() ]
>ng g m SimpleGrid -m app.module --routing
کامپوننتی هم که مثال جاری را نمایش میدهد به صورت ذیل به ماژول SimpleGrid فوق اضافه شدهاست:
>ng g c SimpleGrid/products-list
تهیه معادلهای قراردادهای سمت سرور در سمت Angular
در قسمت قبل، تعدادی قرارداد مانند پارامترهای دریافتی از سمت کلاینت و ساختار اطلاعات ارسالی به سمت کلاینت را تعریف کردیم. اکنون جهت کار strongly typed با آنها در سمت یک برنامهی تایپ اسکریپتی Angular، کلاسهای معادل آنها را تهیه میکنیم.
ساختار شیء محصول دریافتی از سمت سرور
>ng g cl SimpleGrid/app-product
export class AppProduct { constructor( public productId: number, public productName: string, public price: number, public isAvailable: boolean ) {} }
ساختار معادل پارامترهای صفحه بندی و مرتب سازی ارسالی به سمت سرور
>ng g cl SimpleGrid/PagedQueryModel
export class PagedQueryModel { constructor( public sortBy: string, public isAscending: boolean, public page: number, public pageSize: number ) {} }
ساختار معادل اطلاعات صفحه بندی شدهی دریافتی از سمت سرور
>ng g cl SimpleGrid/PagedQueryResult
export class PagedQueryResult<T> { constructor(public totalItems: number, public items: T[]) {} }
ساختار ستونهای گرید نمایشی
>ng g cl SimpleGrid/GridColumn
export class GridColumn { constructor( public title: string, public propertyName: string, public isSortable: boolean ) {} }
تهیه سرویس ارسال اطلاعات صفحه بندی به سرور و دریافت اطلاعات از آن
پس از تدارک این مقدمات، اکنون کار تعریف سرویسی که این اطلاعات را به سمت سرور ارسال میکند و نتیجه را باز میگرداند، به صورت ذیل خواهد بود:
>ng g s SimpleGrid/products-list -m simple-grid.module
پیش از تکمیل این سرویس، نیاز است متدی را جهت تبدیل یک شیء، به معادل کوئری استرینگ آن تهیه کنیم:
toQueryString(obj: any): string { const parts = []; for (const key in obj) { if (obj.hasOwnProperty(key)) { const value = obj[key]; if (value !== null && value !== undefined) { parts.push(encodeURIComponent(key) + "=" + encodeURIComponent(value)); } } } return parts.join("&"); }
[HttpGet("[action]")] public PagedQueryResult<Product> GetPagedProducts(ProductQueryViewModel queryModel)
http://localhost:5000/api/Product/GetPagedProducts?sortBy=productId&isAscending=true&page=2&pageSize=7
پس از این تعریف، سرویس ProductsListService به صورت ذیل تکمیل خواهد شد:
@Injectable() export class ProductsListService { private baseUrl = "api/Product"; constructor(private http: Http) {} getPagedProductsList( queryModel: PagedQueryModel ): Observable<PagedQueryResult<AppProduct>> { return this.http .get(`${this.baseUrl}/GetPagedProducts?${this.toQueryString(queryModel)}`) .map(res => { const result = res.json(); return new PagedQueryResult<AppProduct>( result.totalItems, result.items ); }); }
سپس در متد map آن، res.json دقیقا همان ساختار PagedQueryResult سمت سرور را به همراه دارد. اینجا است که فرصت خواهیم داشت نمونهی سمت کلاینت آنرا که در ابتدای بحث تهیه کردیم، وهله سازی کرده و بازگشت دهیم (نگاشت فیلدهای دریافتی از سمت سرور به سمت کلاینت).
تکمیل کامپوننت نمایش گرید
قسمت آخر این مطلب، استفادهی از این ساختارها و سرویسها و نمایش اطلاعات دریافتی از آنها است. برای این منظور ابتدا نیاز است سرستونهای این گرید را تهیه کرد:
<table class="table table-striped table-hover table-bordered table-condensed"> <thead> <tr> <th class="text-center" style="width:3%">#</th> <th *ngFor="let column of columns" class="text-center"> <div *ngIf="column.isSortable" (click)="sortBy(column.propertyName)" style="cursor: pointer"> {{ column.title }} <i *ngIf="queryModel.sortBy === column.propertyName" class="glyphicon" [class.glyphicon-sort-by-order]="queryModel.isAscending" [class.glyphicon-sort-by-order-alt]="!queryModel.isAscending"></i> </div> <div *ngIf="!column.isSortable" style="cursor: pointer"> {{ column.title }} </div> </th> </tr> </thead>
export class ProductsListComponent implements OnInit { columns: GridColumn[] = [ new GridColumn("Id", "productId", true), new GridColumn("Name", "productName", true), new GridColumn("Price", "price", true), new GridColumn("Available", "isAvailable", true) ];
همچنین در کدهای قالب این کامپوننت، مدیریت کلیک بر روی یک سر ستون را نیز مشاهده میکنید:
export class ProductsListComponent implements OnInit { itemsPerPage = 7; queryModel = new PagedQueryModel("productId", true, 1, this.itemsPerPage); sortBy(columnName) { if (this.queryModel.sortBy === columnName) { this.queryModel.isAscending = !this.queryModel.isAscending; } else { this.queryModel.sortBy = columnName; this.queryModel.isAscending = true; } this.getPagedProductsList(); } }
کار رندر بدنهی اصلی گرید توسط همین چند سطر در قالب آن مدیریت میشود:
<tbody> <tr *ngFor="let item of queryResult.items; let i = index"> <td class="text-center">{{ itemsPerPage * (currentPage - 1) + i + 1 }}</td> <td class="text-center">{{ item.productId }}</td> <td class="text-center">{{ item.productName }}</td> <td class="text-center">{{ item.price | number:'.0' }}</td> <td class="text-center"> <input id="item-{{ item.productId }}" type="checkbox" [checked]="item.isAvailable" disabled="disabled" /> </td> </tr> </tbody> </table>
در اینجا حلقهای بر روی queryResult.items تشکیل شدهاست. این منبع داده به صورت ذیل در کامپوننت متناظر مقدار دهی میشود:
export class ProductsListComponent implements OnInit { itemsPerPage = 7; currentPage: number; numberOfPages: number; isLoading = false; queryModel = new PagedQueryModel("productId", true, 1, this.itemsPerPage); queryResult = new PagedQueryResult<AppProduct>(0, []); constructor(private productsListService: ProductsListService) {} ngOnInit() { this.getPagedProductsList(); } private getPagedProductsList() { this.isLoading = true; this.productsListService .getPagedProductsList(this.queryModel) .subscribe(result => { this.queryResult = result; this.isLoading = false; }); } }
قسمت آخر کار، افزودن کامپوننت نمایش شماره صفحات است:
<div align="center"> <pagination [maxSize]="8" [boundaryLinks]="true" [totalItems]="queryResult.totalItems" [rotate]="false" previousText="‹" nextText="›" firstText="«" lastText="»" (numPages)="numberOfPages = $event" [(ngModel)]="currentPage" (pageChanged)="onPageChange($event)"></pagination> </div> <pre class="card card-block card-header">Page: {{currentPage}} / {{numberOfPages}}</pre>
export class ProductsListComponent implements OnInit { itemsPerPage = 7; currentPage: number; numberOfPages: number; onPageChange(event: any) { this.queryModel.page = event.page; this.getPagedProductsList(); } }
هر زمانیکه کاربر بر روی شمارهای کلیک میکند، رخداد onPageChange فراخوانی شده و در اینحالت تنها کافی است شماره صفحهی درخواستی queryModel جاری را به روزرسانی کرده و سپس آنرا در اختیار متد getPagedProductsList جهت دریافت اطلاعات این صفحهی درخواستی قرار دهیم.
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید.
در نگارشهای اولیهی ASP.NET Core، پشتیبانی از authorization، صرفا توسط ویژگی [Authorize]، قابل اعمال به اکشن متد خاصی بود. برای بهبود تنظیم این قابلیت، میانافزار جدید Authorization به ASP.NET Core 3.0 اضافه شدهاست و تنظیم آن جهت کار با امکانات امنیتی برنامه، الزامی است؛ در غیر اینصورت در حین مرور این صفحات و قسمتهای محافظت شده، برنامه با خطای زیر متوقف خواهد شد:
محل صحیح تعریف میانافزار Authorization در ASP.NET Core 3.0
توصیه شدهاست میانافزار جدید Authorization، با فراخوانی متد UseAuthorization، بلافاصله پس از فراخوانی متد UseAuthentication معرفی شود. در این حالت این میانافزار، با یک Policy پیشفرض تنظیم میشود که قابل تغییر و بازنویسی است:
در مورد مفهوم متد MapDefaultControllerRoute، میتوانید به نظرات تکمیلی مطلب Endpoint routing مراجعه کنید.
در ASP.NET Core 3.0، پس از تنظیمات فوق است که قطعه کد زیر و اعمال فیلتر Authorize، مجددا کار میکند:
روش تعریف فیلتر Authorize به صورت سراسری در ASP.NET Core 3.0
میتوان AuthorizeFilter را به صورت یک فیلتر سراسری (global filter in MVC) تعریف کرد تا به تمام کنترلرها و اکشن متدها اعمال شود. هرچند این روش هنوز هم در ASP.NET Core 3.0 کار میکند، اما روش توصیه شدهی جدید آن به صورت زیر است:
در این حالت با اعمال RequireAuthorization به MapDefaultControllerRoute، سبب خواهیم شد تا اعتبارسنجی کاربر برای استفادهی از تمام قسمتهای برنامه، اجباری شود. در این بین اگر کنترلری و یا اکشن متدی نباید محافظت شود و دسترسی آزادانهی به آنها مدنظر است، میتوان از فیلتر AllowAnonymous استفاده کرد:
سفارشی سازی سیاستهای Authorization در ASP.NET Core 3.0
اگر بخواهیم DefaultPolicy میانافزار Authorization را بازنویسی کنیم، میتوان از متد services.AddAuthorization به صورت زیر استفاده کرد که در آن authentication و داشتن یک Scope خاص را اجباری میکند:
تنظیم سیاستهای دسترسی، زمانیکه هیچ نوع تنظیمی از پیش تعریف نشدهاست
با تنظیم FallbackPolicy، میتوان تمام endpointهایی را که توسط فیلتر [Authorize] و یا ()RequireAuthorization محافظت نشدهاند، محافظت کرد.
DefaultPolicy توسط فیلتر [Authorize] و یا ()RequireAuthorization مورد استفاده قرار میگیرد؛ اما FallbackPolicy زمانی بکار خواهد رفت که هیچ نوع سیاست دسترسی تنظیم نشدهباشد. حالت پیشفرض FallbackPolicy، پذیرش تمام درخواستها بدون اعتبارسنجی است.
کارکرد مثال زیر با مثالهای قبلی که از DefaultPolicy استفاده میکردند، یکی است و هدف آن، اجبار به اعتبارسنجی کاربران در همهجا (تمام endpoints)، منهای مواردی است که از فیلتر AllowAnonymous استفاده میشود:
امکان اعمال سفارشی میانافزار Authorization به Endpointهای مجزا
برای مثال در مبحث «بررسی سلامت برنامه»، فریمورک، اعتبارسنجی درخواستهای آنرا پیش بینی نکردهاست؛ اما اینبار میتوان اعتبارسنجی را به endpoint آن اعمال کرد:
همانطور که مشاهده میکنید، در اینجا RequireAuthorization، به صورت سفارشی به یک endpoint خاص اعمال شدهاست و تنظیمات آن، با تنظیمات سایر قسمتهای برنامه یکی نیست.
Endpoint xyz contains authorization metadata, but a middleware was not found that supports authorization. Configure your application startup by adding app.UseAuthorization() inside the call to Configure(..) in the application startup code.
محل صحیح تعریف میانافزار Authorization در ASP.NET Core 3.0
توصیه شدهاست میانافزار جدید Authorization، با فراخوانی متد UseAuthorization، بلافاصله پس از فراخوانی متد UseAuthentication معرفی شود. در این حالت این میانافزار، با یک Policy پیشفرض تنظیم میشود که قابل تغییر و بازنویسی است:
public void Configure(IApplicationBuilder app) { ... app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); }); }
در ASP.NET Core 3.0، پس از تنظیمات فوق است که قطعه کد زیر و اعمال فیلتر Authorize، مجددا کار میکند:
public class HomeController : ControllerBase { [Authorize] public IActionResult BuyWidgets() { ... } }
میتوان AuthorizeFilter را به صورت یک فیلتر سراسری (global filter in MVC) تعریف کرد تا به تمام کنترلرها و اکشن متدها اعمال شود. هرچند این روش هنوز هم در ASP.NET Core 3.0 کار میکند، اما روش توصیه شدهی جدید آن به صورت زیر است:
public void Configure(IApplicationBuilder app) { ... app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute().RequireAuthorization(); }); }
[AllowAnonymous] public class HomeController : ControllerBase { ... }
سفارشی سازی سیاستهای Authorization در ASP.NET Core 3.0
اگر بخواهیم DefaultPolicy میانافزار Authorization را بازنویسی کنیم، میتوان از متد services.AddAuthorization به صورت زیر استفاده کرد که در آن authentication و داشتن یک Scope خاص را اجباری میکند:
public void ConfigureServices(IServiceCollection services) { ... services.AddAuthorization(options => { options.DefaultPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .RequireScope("MyScope") .Build(); }); }
با تنظیم FallbackPolicy، میتوان تمام endpointهایی را که توسط فیلتر [Authorize] و یا ()RequireAuthorization محافظت نشدهاند، محافظت کرد.
DefaultPolicy توسط فیلتر [Authorize] و یا ()RequireAuthorization مورد استفاده قرار میگیرد؛ اما FallbackPolicy زمانی بکار خواهد رفت که هیچ نوع سیاست دسترسی تنظیم نشدهباشد. حالت پیشفرض FallbackPolicy، پذیرش تمام درخواستها بدون اعتبارسنجی است.
کارکرد مثال زیر با مثالهای قبلی که از DefaultPolicy استفاده میکردند، یکی است و هدف آن، اجبار به اعتبارسنجی کاربران در همهجا (تمام endpoints)، منهای مواردی است که از فیلتر AllowAnonymous استفاده میشود:
public void ConfigureServices(IServiceCollection services) { services.AddAuthorization(options => { options.FallbackPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .RequireScope("MyScope") .Build(); }); } public void Configure(IApplicationBuilder app) { app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); }); } [AllowAnonymous] public class HomeController : ControllerBase { }
امکان اعمال سفارشی میانافزار Authorization به Endpointهای مجزا
برای مثال در مبحث «بررسی سلامت برنامه»، فریمورک، اعتبارسنجی درخواستهای آنرا پیش بینی نکردهاست؛ اما اینبار میتوان اعتبارسنجی را به endpoint آن اعمال کرد:
public void Configure(IApplicationBuilder app) { ... app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints .MapHealthChecks("/healthz") .RequireAuthorization(new AuthorizeAttribute(){ Roles = "admin", }); }); }
نظرات اشتراکها
کتابخانه ImageProcessor Core
تمام NUgetهای ImageProcessor برای net framework هست
برای dotnet core از کدوم nuget باید استفاده کرد؟
اشتراکها