Melengkapi asp.net Core MVC tutorial series: part-1, part-2 dan tulisan ini sebagai part-3.
EntityFrameworkCore
Untuk mengakses database, asp.net core secara default menggunakan EntityFrameworkCore dan Sql Server. EntityFrameworkCore adalah data access technology, ini adalah versi ringan dan cross platform dari EntityFramework. Ada dua cara untuk menggunakan entityframework:
- Code first
- Database first
Tutorial ini menggunakan code first, dimana developer akan membuat class POCO yang menggambarkan relasi antar tabel, struktur tabel beserta kolom-kolomnya. Setelah itu menggunakan entityframework migration dan dotnet cli untuk membuat database di SQL server.
Sedangkan database first, adalah cara tradisional dimana developer membuat database langsung menggunakan SQL management studio. Dan menggunakan perintah SQL atau DDL (database definition language) seperti create database, create table, alter table dsb untuk membuat struktur tabel dan relasinya. Kemudian menggunakan dotnet cli dan entityframework scaffolding untuk membuat dbcontext dan model class menjadi file .cs.
Entityframework dan data migration akan saya jelaskan dalam blogpost berikutnya secara lebih mendalam dan spesifik. Untuk melanjutkan tutorial ini silakan buka folder Models, buat satu file baru; namanya belajaraDbContext.cs. Didalam-nya buat 3 POCO class yaitu TblUser, TblRole dan TblUserRole. TblUser memiliki properti UserName, Password, EmailAddress dan UserID. TblRole memilik 2 properti yaitu: RoleID dan RoleName. Sedangkan TblUserRole memiliki ID, TblUser dan TblRole yang menggambarkan relationship Many To Many antara tabel TblUser dan TblRole.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.ComponentModel.DataAnnotations; | |
using Microsoft.EntityFrameworkCore; | |
namespace belajarnetcoremvc.Models | |
{ | |
public class belajarDbContext :DbContext | |
{ | |
public belajarDbContext(DbContextOptions options) : base(options) | |
{ | |
} | |
public DbSet<TblRole> TblRole { get; set; } | |
public DbSet<TblUser> TblUser { get; set; } | |
public DbSet<TblUserRole> TblUserRole { get; set; } | |
} | |
public class TblUser | |
{ | |
[Key] | |
public int UserID { get; set; } | |
public string UserName { get; set; } | |
public string Password { get; set; } | |
public string EmailAddress { get; set; } | |
} | |
public class TblRole{ | |
[Key] | |
public int RoleID { get; set; } | |
public string RoleName { get; set; } | |
} | |
public class TblUserRole | |
{ | |
[Key] | |
public int ID { get; set; } | |
public TblUser TblUser { get; set; } | |
public TblRole TblRole { get; set; } | |
} | |
} |
Data annotation [Key], untuk menandakan suatu property sebagai Primary Key. Masih banyak data annotations lain yang dapat dilihat di sini.
Register DbContext
Ganti isi Startup.cs dengan mengubah method ConfigureServices dan Configure, seperti di bawah. Dalam ConfiugureServices dengan menambah DbContext object dan menggunakan Sql Server Provider untuk EntityFrameworkCore, pada baris 27 configureservices akan membaca ConnectionString dari appsettings.json. Tambahkan juga dotnet cli tools reference Microsoft.EntityFrameworkCore.Tools.DotNet di dalam belajaraspnetcoremvc.csproj, gunanya untuk melakukan migrations.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using belajarnetcoremvc.Models; | |
using Microsoft.AspNetCore.Authentication.Cookies; | |
using Microsoft.AspNetCore.Builder; | |
using Microsoft.AspNetCore.Hosting; | |
using Microsoft.EntityFrameworkCore; | |
using Microsoft.Extensions.Configuration; | |
using Microsoft.Extensions.DependencyInjection; | |
namespace belajarnetcoremvc | |
{ | |
public class Startup | |
{ | |
public Startup(IConfiguration configuration) | |
{ | |
Configuration = configuration; | |
} | |
public IConfiguration Configuration { get; } | |
// This method gets called by the runtime. Use this method to add services to the container. | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
services.AddDbContext<belajarDbContext>(opt=>{ | |
opt.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")); | |
}); | |
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) | |
.AddCookie(opt=> { | |
opt.LoginPath= new Microsoft.AspNetCore.Http.PathString("/security/login") ; | |
opt.LogoutPath= new Microsoft.AspNetCore.Http.PathString("/security/signout") ; | |
opt.ExpireTimeSpan=TimeSpan.FromMinutes(2); | |
opt.SlidingExpiration=false; | |
opt.AccessDeniedPath="/Security/denied"; | |
}); | |
services.AddMvc(); | |
} | |
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | |
public void Configure(IApplicationBuilder app, IHostingEnvironment env) | |
{ | |
if (env.IsDevelopment()) | |
{ | |
app.UseDeveloperExceptionPage(); | |
} | |
else | |
{ | |
app.UseExceptionHandler("/Home/Error"); | |
} | |
app.UseAuthentication(); | |
app.UseStaticFiles(); | |
app.UseMvcWithDefaultRoute(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"ConnectionStrings":{ | |
"DefaultConnection" :"server=.\\sqlexpress; database=belajarDb;user id=sa;password=[password]" | |
}, | |
"Logging": { | |
"IncludeScopes": false, | |
"LogLevel": { | |
"Default": "Warning" | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project Sdk="Microsoft.NET.Sdk.Web"> | |
<PropertyGroup> | |
<TargetFramework>netcoreapp2.0</TargetFramework> | |
</PropertyGroup> | |
<ItemGroup> | |
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> | |
</ItemGroup> | |
<ItemGroup> | |
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" /> | |
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" /> | |
</ItemGroup> | |
</Project> |
EF Migration & Database update
Lakukan migrasi menggunakan dotnet cli untuk membuat database di SQL Server, ketik perintah beriku di dalam command prompt: dotnet ef migration add initial
kemudian tekan enter dan file initial.cs akan dibuat di dalam folder Migrations, setiap kali semua file di dalam folder ini. Ketik dotnet ef database update
untuk mengupdate database sesuai migration configuration yang ada di initial.cs. Sekarang kita bisa buka database dan lihat didalamnya ada tabel – tabel yang sudah dibuatkan. Langkah berikutnya adalah isikan data di tabel – tabel tersebut seperti di bawah:
RoleID | RoleName |
---|---|
1 | Pembaca |
2 | Penulis |
3 | Administrator |
UserID | EmailAddress | Password | UserName |
---|---|---|---|
1 | testuser@mail.com | passwordtest | usertest |
2 | John@gmail.com | bacasaja | jonBaca |
3 | Henrick@outlook.com | tulisjuga | henWrite |
4 | vasily@outlook.com | passwordvas | vasilyYa |
ID | TblRoleRoleID | TblUserUserID |
---|---|---|
1 | 2 | 2 |
2 | 1 | 2 |
3 | 1 | 3 |
4 | 2 | 3 |
5 | 1 | 1 |
6 | 3 | 4 |
Menambah User Claims
untuk memberikan user autentikasi cookie, maka kita perlu memberikan Claims pada saat user berhasil login. Claims adalah pasangan nama dan nilai yang menggambarkan suatu object. CLaims disetting dengan tipe tertentu dan nilai yang sesuai atau yang kita inginkan, umumnya ClaimType.Name, ClaimType.Email, ClaimType.NameIdentifier dan ClaimType.Role.
Ubah SecurityController dan HomeController seperti dibawah ini, HomeController harus tambahkan [Authorize] attribute di About, Contact action dengan parameter Roles untuk mengarahkan otorisasi yang spesifik untuk role tertentu saja. Contoh dibawah hanya memperbolehkan user dengan role Pembaca dan Penulis yang bisa mengakses Contact dan About page.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class HomeController : Controller | |
{ | |
[Authorize] | |
public IActionResult Index() | |
{ | |
var roles = User.Identities; | |
return View(roles); | |
} | |
[Authorize(Roles="Penulis")] | |
public IActionResult About() | |
{ | |
ViewData["Message"] = "Your application description page." +User.Identity.Name; | |
return View(); | |
} | |
[Authorize(Roles="Pemabaca")] | |
public IActionResult Contact() | |
{ | |
ViewData["Message"] = "Your contact page."+User.Identity.Name;; | |
return View(); | |
} | |
public IActionResult Error() | |
{ | |
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[HttpPost] | |
[AllowAnonymous] | |
[ValidateAntiForgeryToken] | |
public IActionResult Login(LoginViewModel loginViewModel,string ReturnUrl) | |
{ | |
if (ModelState.IsValid) | |
{ | |
// set claimsidentity | |
var user = Db.TblUser.SingleOrDefault(d=> d.UserName==loginViewModel.UserName && d.Password==loginViewModel.Password); | |
if(user!=null) | |
{ | |
var role = (from ur in Db.TblUserRole | |
join r in Db.TblRole on ur.TblRole equals r | |
select new {Role= r.RoleName, ur.TblUser} | |
).ToList(); | |
if(role==null) | |
return View(loginViewModel); | |
var claims =new List<Claim>(); | |
claims.Add(new Claim(ClaimTypes.NameIdentifier, loginViewModel.UserName)); | |
claims.Add(new Claim(ClaimTypes.Name, loginViewModel.UserName)); | |
claims.Add(new Claim(ClaimTypes.Email, loginViewModel.UserName)); | |
foreach (var r in role) | |
{ | |
claims.Add(new Claim(ClaimTypes.Role, r.Role)); | |
} | |
var identity = new ClaimsIdentity(claims,CookieAuthenticationDefaults.AuthenticationScheme); | |
var principal = new ClaimsPrincipal(identity); | |
// set authentication properties | |
var authProps = new AuthenticationProperties{ | |
IsPersistent=false, | |
}; | |
if(!string.IsNullOrEmpty(ReturnUrl)) | |
authProps.RedirectUri=ReturnUrl; | |
var s= SignIn(principal,CookieAuthenticationDefaults.AuthenticationScheme); | |
s.Properties=authProps; | |
return s; | |
} | |
else{ | |
//ModelState.AddModelError("InvalidLogin", new System.Exception("username and password is invalid.")); | |
ModelState.AddModelError(string.Empty, "Username and Password is invalid."); | |
//ViewData["Message"]="Username and Password is invalid."; | |
} | |
} | |
return View(loginViewModel); | |
} |
Autentikasi with Roles
Save file, kemudian run project dengan menekan F5
pada VSCode atau ketik dotnet run -p .belajarnetcoremvc.csproj
di terminal/powershell. Gunakan username dan password yang diisi sebelumnya, buka halam Contact dan About untuk mencoba otorisasi berdasar Role user.
full source code di sini.
entityframework mvc migrations