30 Ağustos 2009 Pazar

Asp.Net MVC ile Kendi Doğrulama Niteliğimizi Yazalım

Uzun bir aradan sonra herkese merhaba. Daha öncede belirttiğim gibi üzerinde çalıştığım bir proje var. Bu yüzden makalelerime ara vermek zorunda kaldım.



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.

12 Ağustos 2009 Çarşamba

Ege Üniversitesi Deri Mühendisliğini Kazandım

Bu sene şansımı denemek istedim ve tekrar üniversiteye girdim. Aslında açık öğretim seçeneği bana pek cazip gelmedi. "Ben okursam örgün okurum arkadaş!" dedim ve böyle bir karar aldım. Neyse belki yatay geçiş ya da çift anadal olanağı vardır. Ben de bunlardan birini değerlendiririm. Hayırlısı olsun diyorum.
Uzun süredir yazmıyorum bu yüzden gerçekten özür dilerim. Yetiştirilmesi gereken bir proje var ve bunun üzerinde çalışıyorum. Ama bahsettim konular hakkında yazılar yazmaya devam edeceğim. Belki sadece java'ya geçiş olayı çok sonra olabilir. Bunların dışında Mvc ve JQuery entegrasyonu ile ilgili pek çok yazı göreceksiniz. Gerçekleştirdiğim projede bir çok şey yaptım ve bunlar eminim çok hoşunuza gidecektir. Bu ay içinde güzel bir yazı geliyor. Görüşmek üzere...

20 Nisan 2009 Pazartesi

Oracle Sun'ı Satın Almış. Peh!

Yahu tam Java'ya geçiş süreci içindeyken yapılır mı bu? Belki sevinen insanlar vardır ama Adobe Macromedia'yı alıncada pek bir yenilik olduğu söylenemez. Yani satın alınan büyük firmalarda rekabetin azalmasından dolayı ne yazıkki büyük yenilikler göremiyoruz.

Peki ne olacak? Büyük bir veritabanı sistemi üreticisi olan Oracle artık Java ile yazılım tarafınada kaymaya başlayacak. Java için pek hayırlı bir olay gözükmüyor. Belki IBM alsa herşey daha güzel olurdu. Ama veritabancıların tek umudu herhalde MySQL'in geliştirilmesi olacaktır.

O zaman şu iki dili paralel yürütme hayalime devam edeyim ben en iyisi...

06 Nisan 2009 Pazartesi

Üniversiteye Hazırlık Süreci

Herkese merhaba...
Bu aralar üniversiteye hazırlanmaya çalışıyorum. O yüzden bloğuma bişeyler yazamıyorum ve sizlerden özür diliyorum.
Yalnız takip eden arkadaşlar için şöyle bir ToDo yaptım (14 Hazirandan sonra bu yazıları bloğumda görebileceksiniz) :

  • Asp.Net MVC ile Kendi Doğrulama Niteliğimizi Yazalım
Bu yazıda [Dogrulama] şeklinde bir attribute yazacağız ve Mvc'deki doğrulama ve yetkilendirme işlemlerimizi kendimiz yapacağız.
  • Java'ya Başlarken
Bu yazı belki bir seri olacak. Java'ya geçiş sürecimi sizlerle bu seride paylaşacağım. Hangi editörü kullanmalıyız, hangi 3. parti bileşenler kullanılıyor hep birlikte inceleyeğiz.
  • JQuery ile Özel DataPicker
JQuery ile kendimize ait, özelleştirebilir bir dataPicker yazacağız.

  • JavaScript MVC
MVC'ye farklı bir açıdan yaklaşıp, javascript ile Model View Controller modelini gerçekleştireceğiz.

Uzun süredir aklımda olan fikirler bunlar.
Sağlıcakla kalın...

25 Mart 2009 Çarşamba

21 Mart Fırat Üniversitesi Yazılım Mimarisi Tasarım Günü

Geçtiğimiz Cumartesi Fırat Üniversitesinde yapılan seminere konuşmacı olarak katıldım. Seminerde Asp.Net MVC 1.0'a değindim. Aslında yeni özelliklerine pek değinemedim ama yeni yazılarımda bu konulara yer vermeye çalışıcam.
Bu arada üniversitedeki hocalarımız bizlerle çok çok ilgilendiler. Onlara teşekkürlerimi tekrar iletiyorum. Ama öğrencileride unutmamak gerek. Sunuma gösterilen katılım ve ilgi gerçekten güzeldi.
Yolculuktan bahsetmek gerekirse; Mehmet Aca, Özcan Acar ve Cihat Altuntaş ile çok keyifli bir yolculuk oldu. Hem biraz teknik konulardan konuştuk, hem de havadan sudan. Umarım yine bir araya geliriz...

Soldan Sağa(Özcan Acar, Ben, Mehmet Aca, Cihat Altuntaş)

18 Mart 2009 Çarşamba

Asp.Net Mvc Release Oldu : Sürüm 1.0

Bu ay içinde release olacağını duyduğumuz ve geçtiğimiz günlerde RC1 ve RC2 versiyonlarını denediğimiz Asp.Net Mvc Framework nihayet 1.0 sürümüne ulaştı. RC sürümlerinden çok fazla farkı olmadığını düşündüğüm bu sürümde sanırım sadece ufak hatalar düzeltildi.

Güle güle kullanın
İndirmek için tıklayın.

08 Mart 2009 Pazar

CopyTaste Dünya Vitrininde

Çok yakın arkadaşım tarafından yazılan site etrafta oldukça ses getirmeye başladı. "CopyPaste has never been so tasty!(KopyalaYapıştır hiç bu kadar lezzetli olmamıştı!)" sloganıyla boy gösteren site, aklınıza gelecebilecek herhangi birşeyi (bu bir yazı , resim veyahut video olabilir) ekleyip sonra bunu paylaşmanıza ya da saklamanıza yarıyor.

Reklam5 A.Ş. tarafından ortaya atılan proje Cnet'de ve bir Alman televizyonunda da gösterildi.

Eğer girişimci biriyseniz ve buna benzer farklı bir fikriniz varsa; bence hayatı bir kenara itip, hemen projenize başlayın.