
Bugün sizlerle birlikte Asp.Net Web Formlar için denediğimiz özel Membership’imizi yani kullanıcı denetleme sistemimizi Asp.Net MVC için yazmaya çalışacağız. Önceki yazımızda Web Form için bu olayı Üst/Taban(Base) bir sınıftan türeterek yaparken, MVC’de sadece doğrulama işleminin gerçekleşmesini istediğimiz sınıfı, Niteliğimizle(Attribute) imzalayarak yapacağız.
Özel Doğrulama Niteliği
Nitelikler(Attributes) bildiğimiz üzere Yansıma(Reflection) teknikleri kullanarak çalışma zamanında nesneler ile ilgili bilgilere erişmemizi sağlarlar. Asp.Net MVC içerisinde yapacağımız bu projede de eski ve kullanımı zor yöntemlerden sıyrılıp çok daha kolay kullanılabilen bir doğrulama sistemi yazacağız. Bunu bize sağlayan şey ise tabiki de Asp.Net MVC’nin esnekliği ve Nitelikler...
Niteliğimizi yazmaya başlamadan önce üye bilgileri tutacağımız MemberInfo ve MemberTicket sınıflarını yazalım.
namespace MvcCustomMembership.Helper
{
public class MemberInfo
{
public string User { get; set; }
public MemberTicket Ticket { get; set; }
public bool IsAuthenticate { get; set; }
}
public class MemberTicket
{
public Guid Guid { get; set; }
public int UserId { get; set; }
public string User { get; set; }
public DateTime IssueDate { get; set; }
public DateTime Expiration { get; set; }
}
}
Bu sınıflarda kullanıcı adı, kullanıcı doğrulandı mı doğrulanmadı mı ve çerez(cookie) için bazı bilgiler içeriyor. Bu bilgileri Session’da tutacağız ve gerektiğinde kullanağız.
Niteliğimizi yazarken ActionFilterAttribute isimli Soyut(Abstract) sınıfdan türettiğimize dikkat ediyoruz. Hatırlayacağınız üzere soyut(Abstract) sınıflar içerisinde tanımlanan soyut metotlar(Abstract Methods) mutlak suretle ezilmelidirler(Override). Şimdi biz de bu metotlardan birini ezerek devre dışı bırakacağız.
public class AuthenticationAttribute : ActionFilterAttribute
{
private HttpContextBase _context;
public Role Roles { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.Controller is ControllerBase)
{
var baseControllar = filterContext.Controller as ControllerBase;
if (baseControllar != null)
{
_context = baseControllar.ControllerContext.HttpContext;
var memberInfo = (MemberInfo)_context.Session["MemberInfo"] ?? new MemberInfo();
Helper.CookieLogin(memberInfo);
if (!memberInfo.IsAuthenticate && _context.Request.Path != null)
{
string loginUrl = "~/Account/Login?returnUrl=" + _context.Request.Path;
filterContext.HttpContext.Response.Redirect(loginUrl);
}
}
}
}
}
OnActionExecuting metodu Controller sınıfı içerisinde tanımlanmış olan bir ActionMethod çalıştırılmak üzereyken işleme alınır. Burada üzerinde bizim niteliğimiz tarafından işaretlenmiş olan bir Controller sınıfı metot gövdesinde kullanılmak üzere parametre ile aktarılıyor. Eğer Session da tanımlanmış olan MemberInfo null değilse memberInfo değişkenine aktarılıyor. Eğer null ise yeni bir MemberInfo sınıfı yaratılıyor. Yaratılma işleminden hemen sonra ise daha önce “Beni Hatırla” seçeneği işaretlenmişse çerez içerinden bilgiler aktarılıp memberInfo sınıfına bu şekilde aktarım gerçekleştiriliyor.
Bir sonraki satırda ise kullanıcının doğrulanma durumu kontrol ediliyor. Doğrulama işlemi gerçekleştirilmemişse kullanıcının hangi sayfadan Login sayfasına yönlendirildiğine dair bir Url bilgisi elde ediliyor. Böylelikle eğer About sayfasına girdiyseniz ve bu sayfada doğrulama işlemi gerekiyorsa, sistem sizi Login sayfasına yönlendiriyor(returnUrl isimli parametre).
Şimdi geçelim AccoutController sınıfımıza. Öncelikle yeni yaratılan MVC proje şablonu içerisindeki AccountController sınıfının gövdesini temizleyelim ve aşağıdaki kod blogunu buraya geçirelim.
[HandleError]
public class AccountController : Controller
{
public ActionResult Index()
{
return RedirectToAction("Login");
}
public ActionResult Login()
{
ViewData["Title"] = "Login Page";
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Login(string username, string password, string rememberMe)
{
//Kullanıcı adı ve şifre kontrollerinide veritabanına bağlanıp yapmalıyız
if (username == "test" && password == "test")
{
string requestUrl = Request.QueryString.Count > 0 ? Request.QueryString["returnUrl"] : null;
//Bu kısımı database'den gelen veriye göre set etmemiz gerekiyor
var memberInfo = new MemberInfo { IsAuthenticate = true, User = "Gokay" };
Session["MemberInfo"] = memberInfo;
memberInfo.Ticket = new MemberTicket()
{
User = memberInfo.User,
Expiration = DateTime.Now.AddMinutes(2),
IssueDate = DateTime.Now,
UserId = 1,
Guid = Guid.NewGuid()
};
if (rememberMe == "on")
AddCookie(memberInfo);
if (requestUrl != null)
return Redirect(requestUrl);
return RedirectToAction("Index", "Home");
}
else
return View();
}
private void AddCookie(MemberInfo memberInfo)
{
var myCookie = new HttpCookie("myCookie");
myCookie.Values.Add("userName", memberInfo.User);
myCookie.Values.Add("userIssueDate", memberInfo.Ticket.IssueDate.ToString());
myCookie.Values.Add("userId", memberInfo.Ticket.UserId.ToString());
myCookie.Values.Add("userGuid", memberInfo.Ticket.Guid.ToString());
myCookie.Values.Add("userExpiration", memberInfo.Ticket.Expiration.ToString());
myCookie.Expires = memberInfo.Ticket.Expiration;
Response.Cookies.Add(myCookie);
}
public ActionResult Logout()
{
Session["MemberInfo"] = null;
if (Request.Cookies["myCookie"] != null)
{
RemoveCookie();
}
return RedirectToAction("Index", "Home");
}
private void RemoveCookie()
{
var myCookie = new HttpCookie("myCookie") { Expires = DateTime.Now.AddYears(-1) };
Response.Cookies.Set(myCookie);
}
}
En üsteki Index isimki ActionResult metodumuz tarayıcıdan http://localhost/Account biçminde bir istek gelirse Login ActionResult’una yönlendirme yapıyor. Login metodu içerisinde ise doğrulama işlemlerini ele alıyoruz. Bunun için bir de Login isimli bir View oluşturmamız gerekiyor. Burada kullanıcı arabirimimizi tasarlayacağız.
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm())
{ %>
<table>
<tr>
<td>
Username :
</td>
<td>
<%= Html.TextBox("username")%>
</td>
</tr>
<tr>
<td>
Password :
</td>
<td>
<%= Html.Password("password")%>
</td>
</tr>
<tr>
<td colspan="2">
<input id="rememberMe" name="rememberMe" type="checkbox"/><label for="rememberMe">Beni Hatırla</label>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="login" id="login" value="Login" />
</td>
</tr>
</table>
<%} %>
</asp:Content>
Login ActionResult metodu içerindeki KullanıcıAdı ve Şifre kontrollerini veritabanına bağlanıp yapabiliriz. Ben burada işlemleri hızlı yapmak adına kullanıcı adı ve şifresiyi “test” olarak belirledim. İf blogunun içine bakmak gerekirse; burada Nitelik içerisinde belirtilen returnUrl isimli parametrenin Url üzerinde olup olmadığını kontrol ediyoruz. Daha sonra memberInfo sınıfını yaratıp, giriş yapan kullanıcının bilgilerini buradaki özelliklere(properties) atıyoruz. “Beni Hatırla” isimli chechBox işaretlenmişse çerezimizi yazıyor ve kullanıcıyı “returnUrl” parametresinde belirtilen adrese ya da anasayfaya yönlendiriyoruz.
Bunların dışında ben anasayfada kullanmak üzere ufak bir UserControl yazdım. Bu UserControl ile Login isimli View içerindeki kodlar birbiriyle oldukça benzer. Bu yüzden sadece UserControl içerisindeki kod bloglarını anlatacağım.
<%
MemberInfo memberInfo = Helper.GetMemberInfo();
if (memberInfo.IsAuthenticate)
{
%>
<span>Hoş Geldiniz
<%= Html.Encode(memberInfo.User) %></span>
<%
}
else
{
using (Html.BeginForm("login", "account", FormMethod.Post))
{
%>
<table>
<tr>
<td>
Kullanıcı Adı
</td>
<td>
<input id="username" name="username" type="text" maxlength="20" size="20" />
</td>
</tr>
<tr>
<td>
Şifre
</td>
<td>
<input id="password" name="password" type="password" maxlength="20" size="20" />
</td>
</tr>
<tr>
<td colspan="2">
<input type="checkbox" id="rememberMe" name="rememberMe" /><label for="rememberMe">Remember
Me</label>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="login" id="login" value="Login" />
</td>
</tr>
</table>
<%
}
}
%>
En üst satırda memberInfo sınıfımızı Helper metodu içerisindeki GetMemberInfo metodu ile set ediyorum
public static class Helper
{
public static MemberInfo GetMemberInfo()
{
var memberInfo = new MemberInfo();
if (HttpContext.Current.Session["MemberInfo"] != null)
memberInfo = (MemberInfo)HttpContext.Current.Session["MemberInfo"];
else
CookieLogin(memberInfo);
return memberInfo;
}
public static void CookieLogin(MemberInfo memberInfo)
{
var myCookie = HttpContext.Current.Request.Cookies["myCookie"];
if (myCookie != null)
{
int userExpration = Convert.ToDateTime(myCookie.Values["userExpiration"]).Year;
int userIssueDate = Convert.ToDateTime(myCookie.Values["userIssueDate"]).Year;
if (myCookie["userName"] != null && !memberInfo.IsAuthenticate && userExpration >= userIssueDate)
{
memberInfo.User = myCookie["userName"];
memberInfo.Ticket = new MemberTicket()
{
User = myCookie["userName"],
Guid = new Guid(myCookie["userGuid"]),
UserId = Convert.ToInt32(myCookie["userId"])
};
//Eğer belirtilen guid database'de bulunuyorsa isAuthenticate property'sini true yapalım
memberInfo.IsAuthenticate = true;
}
}
}
}
Doğrulama işlemi başarılı gerçekleştirilmişse “Hoş Geldiniz” yazısını ve kullanıcı ismini gösteriyor, gerçekleştirilmemiş ise giriş yapma arabiriminiz gösteriyorum. Burada dikkat etmemiz gereken bir ikinci kısım ise buradaki belirtilen form’un yani BeginForm ile başlayan kısımın metot özelliğini “Post” olarak atıyoruz(Parametrelerden diğer ikisi ise ActionName ve Controller Name’i belirtiyor). Belirtilen bu metodun çalışması için Controller sınıfı içerindeki Login metodu üzerinide [AcceptVerbs(HttpVerbs.Post)] niteliğini tanımlıyoruz.
Şimdi geldi buraya kadar yaptıklarımızı denemeye. Hemen HomeController sınıfımıza giriyoruz ve About isimli metodumuzun üzerinde niteliğimizi yazıyoruz.
[Authentication(Roles = Role.User)]
public ActionResult About()
{
return View();
}
Eğer istersek kullanıcı rollerinide belirtip role göre login işlemlerini gerçekleştirebiliriz.
Geldik bir yazımızın sonuna daha... Farklı bir konuda, farklı bir yazıda görüşmek üzere esen kalın.
Örneği indirmek için tıklayın.








