📖 Proces Prijave i Registracije
Implementacija sistema za kreiranje novih naloga i njihovu autentifikaciju. U sistemima javne uprave, registracija je često zatvorena (samo administratori kreiraju naloge), ali mehanizam "Lockout"-a prilikom prijave je od krucijalne važnosti za odbranu od Brute-Force pogađanja lozinki.
➕ Kontroler Registracije
Ovaj primjer prikazuje kreiranje korisnika uz pomoć UserManager-a, uz automatsku dodjelu
početne uloge (Role).
[HttpPost]
[AllowAnonymous] // Dozvoljeno svima da pristupe čak i ako je kontroler zaključan
[ValidateAntiForgeryToken]
public async Task Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
// 1. Priprema objekta baziranog na ViewModelu
var user = new ApplicationUser {
UserName = model.Email,
Email = model.Email,
Ime = model.Ime,
Prezime = model.Prezime,
JMBG = model.JMBG,
DatumZaposlenja = DateTime.Now,
OrganizacionaJedinicaId = model.SektorId
};
// 2. Kreiranje korisnika. Identity OVDE u pozadini vrši Hashiranje lozinke
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// 3. Dodjeljivanje osnovne role (ako RoleManager postoji)
await UserManager.AddToRoleAsync(user.Id, "Sluzbenik");
// Opcionalno: Šaljemo email za potvrdu računa (Email Confirmation)
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// ...
// 4. Automatska prijava nakon registracije
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
return RedirectToAction("Index", "Pocetna");
}
// Ako je puklo (npr. prekratka lozinka, email zauzet), dodajemo Identity greške u ModelState
AddErrors(result);
}
// Ako ModelState nije validan, vrati formu nazad sa istim podacima
return View(model);
}
🔐 Sistem Prijave sa Lockout Zaštitom
Kada se korisnik prijavljuje, SignInManager provjerava bazu, poredi Hash lozinke i izdaje
Auth Cookie.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid) return View(model);
// shouldLockout: true je KRITIČNO ZBOG SIGURNOSTI!
// Ako korisnik 5 puta (po defaultu) unese pogrešnu sifru, nalog se zaključava na 15 minuta.
var result = await SignInManager.PasswordSignInAsync(
model.Email, model.Password, model.RememberMe, shouldLockout: true);
switch (result)
{
case SignInStatus.Success:
// returnUrl ga vraća tamo gdje je prvobitno htio ići prije nego što je preusmjeren na login
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
// Preusmjerimo na poseban pogled koji kaže "Nalog je zaključan zbog sigurnosti"
return View("Lockout");
case SignInStatus.RequiresVerification:
// Koristi se za 2FA (Two-Factor Authentication) npr. SMS kod
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
// NIKAD ne govorite "Lozinka je pogrešna". Recite "Neispravni podaci".
// Ako kažete "Pogrešna lozinka", haker zna da email ustvari POSTOJI u bazi.
ModelState.AddModelError("", "Neispravni podaci za prijavu.");
return View(model);
}
}
🛡️ Autorizacija (Role-based) putem filtera
Autentifikacija pita "Ko si ti?". Autorizacija pita "Imaš li dozvolu za ovo?".
ASP.NET MVC koristi [Authorize] filter. Ukoliko korisnik zatraži akciju za koju nema
dozvolu, MVC ga automatski prebaci na Login ekran sa kodom 401.
// Pristup samo za prijavljene korisnike.
// Gosti (Anonymous) ne mogu otvoriti Dashboard.
[Authorize]
public ActionResult Dashboard()
{
return View();
}
// Pristup ima SAMO korisnik koji ima Role 'Administrator'.
// Uloga se čita direktno iz Auth Cookie-ja.
[Authorize(Roles = "Administrator")]
public ActionResult KreirajBudzet()
{
return View();
}
// Pristup za više različitih uloga (bilo koja od ovih prolazi)
[Authorize(Roles = "Ministar, Inspektor, StrucniSavjetnik")]
public ActionResult PregledPovjerljivihDokumenata(int id)
{
// Logika prikaza
}
🌍 Globalna Autorizacija (Best Practice za Javnu Upravu)
U nekim sistemima 99% aplikacije je tajno, a samo Login stranica je javna. Bolje je zaključati cijelu
aplikaciju na nivou Global.asax / FilterConfig klase, nego pisati [Authorize] iznad svakog
kontrolera!
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
// ZAKLJUČAJ CIJELU APLIKACIJU
filters.Add(new AuthorizeAttribute());
}
}
Kako onda pristupiti Login stranici?
Kada zaključate cijelu aplikaciju globalno, morate dodati atribut [AllowAnonymous] iznad
AccountController-a ili iznad same Login akcije kako bi aplikacija uopšte
omogućila korisniku da se prijavi.
✅ Zaključak
Sa Identity SignIn/User menadžerima kreiranje robusnog sistema prijave sa modernim sigurnosnim zahtjevima
(kao što su Lockout i Password Hashing) se svodi na svega par linija koda, dok nam Role-based
Authorization i [Authorize] filteri pružaju granularnu kontrolu pristupa državnim resursima
aplikacije.