Otorisasi sederhana di ASP.NET Core

Otorisasi di ASP.NET Core dikontrol dengan [Authorize] atribut dan berbagai parameternya. Dalam bentuk yang paling dasar, menerapkan atribut ke pengontrol, tindakan, atau Razor Halaman, membatasi akses ke komponen tersebut [Authorize] ke pengguna yang diautentikasi.

Prasyarat

Artikel ini mengasumsikan bahwa Anda memiliki pemahaman dasar tentang ASP.NET Core Razor Pages dan MVC. Jika Anda baru menggunakan ASP.NET Core, lihat sumber daya berikut:

[Authorize] Gunakan atribut

Kode berikut membatasi akses ke pengguna yang diautentikasi AccountController :

[Authorize]
public class AccountController : Controller
{
    public ActionResult Login()
    {
    }

    public ActionResult Logout()
    {
    }
}

Jika Anda ingin menerapkan otorisasi ke tindakan daripada pengontrol, terapkan AuthorizeAttribute atribut ke tindakan itu sendiri:

public class AccountController : Controller
{
   public ActionResult Login()
   {
   }

   [Authorize]
   public ActionResult Logout()
   {
   }
}

Sekarang hanya pengguna yang diautentikasi yang Logout dapat mengakses fungsi.

Anda juga dapat menggunakan AllowAnonymous atribut untuk mengizinkan akses oleh pengguna yang tidak diautentikasi ke tindakan individual. Contohnya:

[Authorize]
public class AccountController : Controller
{
    [AllowAnonymous]
    public ActionResult Login()
    {
    }

    public ActionResult Logout()
    {
    }
}

Ini hanya akan memungkinkan pengguna terautentikasi ke AccountController, kecuali untuk Login tindakan, yang dapat diakses oleh semua orang, terlepas dari status diautentikasi atau tidak diautentikasi / anonim mereka.

Peringatan

[AllowAnonymous] melewati pernyataan otorisasi. Jika Anda menggabungkan [AllowAnonymous] dan atribut [Authorize] , [Authorize] atribut akan diabaikan. Misalnya jika Anda menerapkan [AllowAnonymous] di tingkat pengontrol:

  • Persyaratan otorisasi apa pun dari [Authorize] atribut pada pengontrol atau metode tindakan yang sama pada pengontrol diabaikan.
  • Middleware autentikasi tidak memiliki sirkuit pendek tetapi tidak perlu berhasil.

Kode berikut membatasi akses ke LogoutModelRazor Halaman untuk pengguna terautentikasi:

[Authorize]
public class LogoutModel : PageModel
{
    public async Task OnGetAsync()
    {

    }

    public async Task<IActionResult> OnPostAsync()
    {

    }
}

Untuk informasi tentang cara mengharuskan semua pengguna diautentikasi secara global, lihat Memerlukan pengguna yang diautentikasi.

Mengotorisasi atribut dan Razor Halaman

AuthorizeAttribute Tidak dapat diterapkan ke Razor penangan Halaman. Misalnya, [Authorize] tidak dapat diterapkan ke OnGet, , OnPostatau handler halaman lainnya. Pertimbangkan untuk menggunakan pengontrol MVC Core ASP.NET untuk halaman dengan persyaratan otorisasi yang berbeda untuk penangan yang berbeda. Menggunakan pengontrol MVC ketika persyaratan otorisasi yang berbeda diperlukan:

  • Adalah pendekatan yang paling tidak kompleks.
  • Adalah pendekatan yang direkomendasikan oleh Microsoft.

Jika Anda memutuskan untuk tidak menggunakan pengontrol MVC, dua pendekatan berikut dapat digunakan untuk menerapkan otorisasi ke Razor metode handler Halaman:

  • Gunakan halaman terpisah untuk penangan halaman yang memerlukan otorisasi yang berbeda. Pindahkan konten bersama ke dalam satu atau beberapa tampilan parsial. Jika memungkinkan, ini adalah pendekatan yang direkomendasikan.

  • Untuk konten yang harus berbagi halaman umum, tulis filter yang melakukan otorisasi sebagai bagian dari IAsyncPageFilter.OnPageHandlerSelectionAsync. Proyek PageHandlerAuth GitHub menunjukkan pendekatan ini:

    [TypeFilter(typeof(AuthorizeIndexPageHandlerFilter))]
    public class IndexModel : PageModel
    {
        private readonly ILogger<IndexModel> _logger;
    
        public IndexModel(ILogger<IndexModel> logger)
        {
            _logger = logger;
        }
    
        public void OnGet()
        {
    
        }
    
        public void OnPost()
        {
    
        }
    
        [AuthorizePageHandler]
        public void OnPostAuthorized()
        {
    
        }
    }
    
    public class AuthorizeIndexPageHandlerFilter : IAsyncPageFilter, IOrderedFilter
    {
        private readonly IAuthorizationPolicyProvider policyProvider;
        private readonly IPolicyEvaluator policyEvaluator;
    
        public AuthorizeIndexPageHandlerFilter(
            IAuthorizationPolicyProvider policyProvider,
            IPolicyEvaluator policyEvaluator)
        {
            this.policyProvider = policyProvider;
            this.policyEvaluator = policyEvaluator;
        }
    
        // Run late in the selection pipeline
        public int Order => 10000;
    
        public Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) => next();
    
        public async Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
        {
            var attribute = context.HandlerMethod?.MethodInfo?.GetCustomAttribute<AuthorizePageHandlerAttribute>();
            if (attribute is null)
            {
                return;
            }
    
            var policy = await AuthorizationPolicy.CombineAsync(policyProvider, new[] { attribute });
            if (policy is null)
            {
                return;
            }
    
            await AuthorizeAsync(context, policy);
        }
    
        #region AuthZ - do not change
        private async Task AuthorizeAsync(ActionContext actionContext, AuthorizationPolicy policy)
        {
            var httpContext = actionContext.HttpContext;
            var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, httpContext);
            var authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult, httpContext, actionContext.ActionDescriptor);
            if (authorizeResult.Challenged)
            {
                if (policy.AuthenticationSchemes.Count > 0)
                {
                    foreach (var scheme in policy.AuthenticationSchemes)
                    {
                        await httpContext.ChallengeAsync(scheme);
                    }
                }
                else
                {
                    await httpContext.ChallengeAsync();
                }
    
                return;
            }
            else if (authorizeResult.Forbidden)
            {
                if (policy.AuthenticationSchemes.Count > 0)
                {
                    foreach (var scheme in policy.AuthenticationSchemes)
                    {
                        await httpContext.ForbidAsync(scheme);
                    }
                }
                else
                {
                    await httpContext.ForbidAsync();
                }
    
                return;
            }
        }
    

Peringatan

Pendekatan sampel PageHandlerAuth tidak:

  • Buat dengan atribut otorisasi yang diterapkan ke halaman, model halaman, atau secara global. Menyusun atribut otorisasi menghasilkan autentikasi dan otorisasi yang dijalankan beberapa kali ketika Anda memiliki satu lagi AuthorizeAttribute atau AuthorizeFilter instans juga diterapkan ke halaman.
  • Bekerja bersama dengan sistem autentikasi dan otorisasi ASP.NET Core lainnya. Anda harus memverifikasi bahwa menggunakan pendekatan ini berfungsi dengan benar untuk aplikasi Anda.

Tidak ada rencana untuk mendukung penanganan AuthorizeAttribute Halaman Razor .