[Authorize] va [AllowAnonymous] — route himoya qilish

~15 daq · .NET Backend · Autentifikatsiya va Avtorizatsiya

Muammodan boshlaylik

JwtBearer sozlandi (60-dars), token ishlaydi. Lekin GET /api/buyurtmalar ga tokensiz so'rov yuborilsa — hammasi qaytadi. Middleware tokenni tekshiradi va User ni to'ldiradi, ammo hech kim "bu endpoint ga faqat kirgan foydalanuvchi" deb aytmagan.

Autentifikatsiya (kim?) va avtorizatsiya (ruxsat bormi?) — ikki alohida bosqich.

Autentifikatsiya Avtorizatsiya
Savol Siz kimsiz? Sizga bu mumkinmi?
Xato 401 Unauthorized 403 Forbidden
Misol Token yaroqli Admin emas — o'chira olmaydi

Hayotiy o'xshatma

Mehmonxona. Qabulxonada pasport ko'rsatasiz — kim ekaningiz aniqlandi (autentifikatsiya). Kartangiz faqat 305-xona va zalni ochadi — boshqa xonalar yopiq (avtorizatsiya). Restoran va qabulxona esa hamma uchun ochiq (AllowAnonymous).


[Authorize] — faqat kirganlar

[ApiController]
[Route("api/buyurtmalar")]
[Authorize]                                  // butun controller
public class BuyurtmalarController(DokonDbContext db) : ControllerBase
{
    [HttpGet]
    public async Task<IActionResult> Meniki(CancellationToken ct)
    {
        var id = User.FoydalanuvchiId();
        return Ok(await db.Buyurtmalar.Where(b => b.MijozId == id).ToListAsync(ct));
    }
}
  • Token yo'q / yaroqsiz / muddati o'tgan — 401, action ishga tushmaydi
  • Token yaroqli — action bajariladi, User to'ldirilgan

[AllowAnonymous] — istisno

[ApiController]
[Route("api/mahsulotlar")]
[Authorize]
public class MahsulotlarController : ControllerBase
{
    [HttpGet]
    [AllowAnonymous]                         // katalogni hamma ko'radi
    public IActionResult Royxat() => Ok(...);

    [HttpPost]                               // qo'shish — faqat kirganlar
    public IActionResult Yarat(MahsulotYaratDto dto) => ...;
}

[AllowAnonymous] har qanday [Authorize] ni (controller va global darajadagini ham) bekor qiladi.


Global himoya — "sukut bo'yicha yopiq"

Har bir controller ga [Authorize] yozishni unutish oson. Teskarisi xavfsizroq — hammasini yopib, ochiqlarini aniq belgilash:

builder.Services.AddAuthorization(o =>
{
    o.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

Endi atributsiz har bir endpoint ham autentifikatsiya talab qiladi; login, ro'yxatdan o'tish, health check — [AllowAnonymous].

[HttpPost("login")]
[AllowAnonymous]
public async Task<ActionResult<TokenJavob>> Login(LoginDto dto, CancellationToken ct) { ... }

[!TIP] "Sukut bo'yicha yopiq" (secure by default) — yangi endpoint qo'shilsa va himoya unutilsa ham, u ochiq qolib ketmaydi. Eng yomon holatda — kimdir 401 olib, [AllowAnonymous] qo'shish kerakligini sezadi; bu sizib chiqqan ma'lumotdan ko'ra ancha yaxshi.


Policy — nomlangan qoidalar

builder.Services.AddAuthorization(o =>
{
    o.AddPolicy("EmailTasdiqlangan", p => p.RequireClaim("email_verified", "true"));
    o.AddPolicy("Admin", p => p.RequireRole("admin"));
    o.AddPolicy("Kattalar", p => p.RequireAssertion(ctx =>
        int.TryParse(ctx.User.FindFirstValue("yosh"), out var y) && y >= 18));
});
[Authorize(Policy = "EmailTasdiqlangan")]
[HttpPost("buyurtma")]
public IActionResult Buyurtma(...) => ...;

Bir nechta [Authorize] atributi — barchasi bajarilishi kerak (AND).


Resurs egasini tekshirish

[Authorize] "kirganmi?" deb so'raydi, lekin "bu buyurtma unikimi?" deb so'ramaydi:

[HttpGet("{id:int}")]
public async Task<IActionResult> Ol(int id, CancellationToken ct)
{
    var b = await db.Buyurtmalar.FindAsync([id], ct);
    if (b is null) return NotFound();

    if (b.MijozId != User.FoydalanuvchiId() && !User.IsInRole("admin"))
        return NotFound();       // yoki Forbid() — mavjudligini ham oshkor qilmaslik uchun 404

    return Ok(b);
}

[!WARNING] IDOR (Insecure Direct Object Reference) — eng keng tarqalgan API zaifliklaridan biri: /api/buyurtmalar/1001 ni /1002 ga o'zgartirib, boshqaning ma'lumotini ko'rish. Har bir ID bo'yicha so'rovda egalikni tekshiring — yoki so'rovning o'zida filtrlang: Where(b => b.Id == id && b.MijozId == meningId).


Minimal API da

app.MapGet("/api/profil", (ClaimsPrincipal user) => user.FindFirstValue(ClaimTypes.Email))
   .RequireAuthorization();

app.MapGet("/api/admin/statistika", () => ...)
   .RequireAuthorization("Admin");

app.MapGet("/api/salom", () => "Salom").AllowAnonymous();

Tez-tez uchraydigan xatolar

UseAuthorization yo'q — [Authorize] bor endpoint lar ishlashdan to'xtaydi (xato bilan); middleware kerak.

401 va 403 ni aralashtirish — tokensiz → 401; token bor, huquq yo'q → 403.

Faqat [Authorize] ga ishonish — resurs egaligi alohida tekshiriladi (IDOR).


Xulosa

Autentifikatsiya — kim (401), avtorizatsiya — ruxsat (403). [Authorize] — controller yoki action ni faqat kirganlarga; [AllowAnonymous] — istisno. FallbackPolicy + RequireAuthenticatedUser — hammasi sukut bo'yicha yopiq, ochiqlari aniq belgilanadi.

Policy — nomlangan qoidalar (RequireClaim, RequireRole, RequireAssertion), [Authorize(Policy = "...")]. Resurs egaligi — har bir ID so'rovida alohida tekshiriladi (IDOR). Minimal API: RequireAuthorization(), AllowAnonymous().


Keyingi dars

62-dars: Refresh Token — uzoq muddatli sessiya, rotatsiya