16 Mei 20246
Authorization adalah proses untuk melakukan cek hak akses user untuk menentukan apakah user bisa mengakses bagian-bagian yang ada pada aplikasi.
Contoh yang sering biasanya teman-teman temui adalah user yang mempunyai role seperi Admin
dan User
.
Kedua role ini memiliki akses yang berbeda. Lazimnya, role Admin
mempunyai hak akses yang lebih tinggi daripada role User
, misalnya menambahkan atau menghapus user.
Pada tutorial ini, kita menambahkan proses authorization kepada user pada boilerplate.
Kemudian kita akan melakukan cek kepada user dengan dua role yaitu Admin
dan User
.
Pertama, kita buat terlebih dahulu fitur untuk mengelola seluruh user yang ada di aplikasi ini yaitu UserManagement
dengan role Admin
dan User
.
User dengan role Admin
mempunyai akses untuk menambah, menghapus, atau memodifikasi data-data seluruh user di aplikasi serta akses ke halaman-halaman UserManagement
,
sedangkan role User
hanya bisa mengakses data user tersebut
tanpa bisa mengakses data user lain dan tidak bisa melihat halaman-halaman UserManagement
.
Langkah selanjutnya adalah membuat halaman-halaman UserManagement
.
Buat folder Pages/UserManagement
kemudian buat file-file ini di dalam folder baru tersebut.
Kita akan gunakan Index.cshtml
dan Index.cshtml.cs
untuk rute UserManagement
sedangkan halaman-halaman
lain akan kita update nanti. Buka Index.cshtml.cs
dan tambahkan kode berikut.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace BoilerplateWebApp.Pages;
[Authorize(Roles = "Admin")] // Penambahan info protected page sesuai role
public class UserManagementModel : PageModel
{
private readonly ILogger<UserManagementModel> _logger;
public UserManagementModel(ILogger<UserManagementModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
File ini merupakan Page Model yang digunakan pada Index.cshtml
. Authorization user dengan
role Admin
sudah ditambahkan sehingga UserManagementModel
hanya bisa diakses oleh user dengan
role Admin
. User dengan role lain akan gagal untuk mengakses halaman ini.
Selanjutnya, tambahkan kode ini pada file Index.cshtml
.
@page
@model UserManagementModel
@{
ViewData["Title"] = "User Management";
}
<h1>User Management</h1>
<p>List User</p>
File ini akan ditampilkan di frontend.
Setelah itu, buka Program.cs
dan tambahkan role services AddRoles<IdentityUser>()
.
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using BoilerplateWebApp.Data;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityUser>() // menambahkan role services
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
var app = builder.Build();
// Penambahan default admin user
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
await SeedData.Initialize(services);
}
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
...
// kode lanjutan di Program.cs
Langkah selanjutnya adalah membuat seed pada database kita untuk menambahkan default user dengan role Admin
.
Buat file SeedData.cs
di folder Data
dan update file menjadi seperti ini.
using Microsoft.AspNetCore.Identity;
namespace BoilerplateWebApp.Data;
public static class SeedData
{
public static async Task Initialize(IServiceProvider serviceProvider)
{
var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
var userManager = serviceProvider.GetRequiredService<UserManager<IdentityUser>>();
string[] roles = { "Admin", "User" };
foreach (var role in roles)
{
if (!await roleManager.RoleExistsAsync(role))
{
await roleManager.CreateAsync(new IdentityRole(role));
}
}
var adminUser = new IdentityUser
{
UserName = "[email protected]",
Email = "[email protected]",
EmailConfirmed = true
};
var user = await userManager.FindByEmailAsync(adminUser.Email);
if (user == null)
{
var result = await userManager.CreateAsync(adminUser, "Admin@123");
if (result.Succeeded)
{
await userManager.AddToRoleAsync(adminUser, "Admin");
}
}
}
}
File ini berfungsi untuk membuat role Admin
dan User
serta satu user dengan role Admin
yaitu [email protected]
pada database. Role dan user dibuat dengan menggunakan beberapa class
dari Microsoft.AspNetCore.Identity
seperti IdentityRole
dan IdentityUser
.
Apabila user yang akan dibuat serta role belum eksis, maka seed akan dibuat berdasarkan informasi yang ada di file ini.
Okay mari kita jalankan aplikasi ini untuk tes fungsi Authorization yang ada. Jalankan dengan perintah
dotnet run
. Selanjutnya login dengan email [email protected]
dan password Admin@123
.
Setelah itu, teman-teman bisa mengunjungi rute UserManagement
dan akan melihat tampilan pada halaman
UserManagement
sesuai file Pages/UserManagement/Index.cshtml
.
Kemudian teman-teman bisa mencoba register user baru dan juga melakukan klik pada tautan confirm email. User ini nantinya
secara default memang tidak akan memiliki role Admin
. Lalu teman-teman bisa mengunjungi rute UserManagement
lagi. Maka akan ada informasi
Access Denied. Hal ini sesuai dengan skenario Authorization yang kita buat tadi.
Selanjutnya, kita perlu memodifikasi proses registrasi user. Proses registrasi user saat ini tidak dilengkapi dengan penambahan informasi role pada user. Skenario ini harus kita ubah seperti berikut agar aplikasi web ini lebih aman.
User
.User
menjadi Admin
.Buka file Areas/Identity/Pages/Account/Register.cshtml.cs
. Kita tambahkan AddToRoleAsync
dengan role User
saat
pembuatan user di proses registrasi pada method OnPostAsync
sehingga menjadi seperti berikut.
...
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl ??= Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
var user = CreateUser();
await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
var result = await _userManager.CreateAsync(user, Input.Password);
await _userManager.AddToRoleAsync(user, "User"); // Menambahkan default role saat user registrasi
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
if (_userManager.Options.SignIn.RequireConfirmedAccount)
{
return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
}
else
{
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
...
Setelah mengubah file ini, user akan mempunyai role User
pada proses registrasi.
Langkah selanjutnya adalah membuat menu User Management di navbar yang hanya muncul oleh user dengan role Admin
.
Buka file Pages/Shared/_Layout.cshtml
dan tambahkan menu UserManagement
.
...
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
</li>
@{
// Penambahan Menu User Management
}
@if (User.IsInRole("Admin"))
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/UserManagement/Index">User Management</a>
</li>
}
</ul>
<partial name="_LoginPartial" />
</div>
...
Kemudian jalankan aplikasi web kembali. Ketika teman-teman login melalui user dengan role Admin
maka akan terlihat
menu User Management di navbar. User dengan role selain Admin
tidak akan bisa melihat menu ini.
Proses authorization sudah berjalan dengan baik pada boilerplate ini. Kawan-kawan bisa menambahkan role lain sesuai dengan kebutuhan aplikasi yang dibuat. Pada bagian selanjutnya, kita akan menambahkan fitur user management untuk aplikasi ini.
Happy Coding!