احراز هویت در فرم ها با استفاده از Cookie در MVC

شنبه 27 خرداد 1396

در این مقاله به کمک یک مثال عملی نحوه پیاده سازی مکانیزم احرازهویت برای فرم ها با استفاده از FormsAuthenticationTicket (Cookie) در ASP.Net MVC Razor را آموزش می دهیم.

احراز هویت در فرم ها با استفاده از Cookie در MVC

در این مقاله نحوه احراز هویت فرم ها به کمک یک روش سفارشی شده و استفاده از Entity Framework در داخل برنامه هایASP.Net MVC Razor توضیح داده شده است.

 پیکربندی Bundle ها و فعال کردن اعتبار سنجی در سمت Client

فرم لاگین برای احراز هویت کاربر در سمت Client  به کمک جی کوئری و Model Data Annotations  اجرا خواهد شد. برای پیکربندی Bundle ها و فعال کردن Client Side validation، مقاله های موجود در سایت در این رابطه را مطالعه کنید.

نکته: به طور پیش فرض اعتبارسنجی توسط صفت های Data Annotation در سمت سرور انجام می شود. بنابراین اگر بخواهیم این عملیات در سمت Client انجام شود، باید Client Side validation را فعال کنیم.

Database

در داخل دیتابیس یک جدول مربوط به کاربر خواهیم داشت.

نکته: فایل SQL دیتابیس در فایل ضمیمه مقاله موجود است.

ساخت یک Stored Procedure برای اعتبارسنجی اطلاعات کاربر

stored procedure معرفی شده در پایین، برای اعتبارسنجی اطلاعات کاربر مورد استفاده قرار می گیرد. این stored procedure ابتدا بررسی می کند که نام کاربری و رمز عبور درست هستند یا خیر و در صورت مشکل داشتن مقدار -1 برمی گرداند.

اگر نام کاربری و رمز عبور درست بودند ولی کاربر هنوز فعال نشده باشد، پس مقدار -2 برگردانده داده می شود.

اگر نام کاربری و رمز عبور درست باشد و کاربر فعال هم باشد مقدار UserId کاربر به عنوان خروجی، برگردانده می شود.

CREATE PROCEDURE [dbo].[Validate_User]
      @Username NVARCHAR(20),
      @Password NVARCHAR(20)
AS
BEGIN
      SET NOCOUNT ON;
      DECLARE @UserId INT, @LastLoginDate DATETIME
     
      SELECT @UserId = UserId, @LastLoginDate = LastLoginDate
      FROM Users WHERE Username = @Username AND [Password] = @Password
     
      IF @UserId IS NOT NULL
      BEGIN
            IF NOT EXISTS(SELECT UserId FROM UserActivation WHERE UserId = @UserId)
            BEGIN
                  UPDATE Users
                  SET LastLoginDate = GETDATE()
                  WHERE UserId = @UserId
                  SELECT @UserId [UserId] -- User Valid
            END
            ELSE
            BEGIN
                  SELECT -2 -- User not activated.
            END
      END
      ELSE
      BEGIN
            SELECT -1 -- User invalid.
      END
END

 افزودن یک Stored Procedure جدید به Entity Framework Data Model

نحوه تنظیمات و پیکربندی Entity Framework را در مقالات قبلی توضیح داده ایم، پس وارد مرحله بعدی می شویم. در این مرحله قصد اضافه کردن یک Stored Procedure به یک Entity Framework Data Model را داریم.

برای این کار، ابتدا User Data Model را باز کنید و روی جدول User Table راست کلیک کنید و از منو باز شده گزینه Update Model from Database را انتخاب کنید.

عملی که در بالا انجام دادیم باعث می شود که پنجره Update Wizard باز شود و در آن پنجره شما باید Stored Procedure جدید را انتخاب کنید و گزینه Finish را انتخاب کنید.

بعد از اینکه Stored Procedure اضافه شد، لازم است که دوباره روی User Table راست کلیک کرده و گزینه Add New را بزنید و سپس از منو نمایش داده شده گزینه Function Import را انتخاب کنید.

کاری که در بالا انجام دادیم باعث می شود پنجره Add Function Import باز شود.

1- Function Import Name: مشخص کردن نام متدی که قرار است Stored Procedure را اجرا کند.

2-Stored Procedure / Function Name: انتخاب Stored Procedure / Function که قصد انتقال آن را داریم.

3-Returns a Collection Of: در این مقاله از Stored Procedure استفاده شده است که خروجی آن یک مقدار عددی است و به این دلیل گزینه Int32 انتخاب شده است.

در آخر که تمامی مراحل بالا را انجام دادید کلید OK را بزنید.

Model

کلاس User.cs از روی جدول کاربران که در دیتابیس ساخته ایم ایجاد شده است.

namespace User_Login_MVC
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
 
    public partial class User
    {
        public int UserId { get; set; }
 
        [Required(ErrorMessage = "Required.")]
        public string Username { get; set; }
 
        [Required(ErrorMessage = "Required.")]
        public string Password { get; set; }
 
        [Required(ErrorMessage = "Required.")]
        [Compare("Password", ErrorMessage = "Passwords do not match.")]
        public string ConfirmPassword { get; set; }
 
        [Required(ErrorMessage = "Required.")]
        [EmailAddress(ErrorMessage = "Invalid email address.")]
        public string Email { get; set; }
 
        public System.DateTime CreatedDate { get; set; }
 
        public Nullable<System.DateTime> LastLoginDate { get; set; }
 
        public bool RememberMe { get; set; }
    }
}

  

Namespaces

شما باید namespace زیر را به پروژه اضافه کنید.

using System.Web.Security;

Controller

کنترلر ما شامل 4 اکشن متد است.

اکشن متد برای لاگین که مسئول مدیریت عملیات های GET است

در داخل این اکشن متد، یک View به عنوان خروجی فرستاده می شود. این اکشن متد دارای صفت [AllowAnonymous] است که به معنای این است که کاربرانی که احراز هویت نشده اند هم قابلیت دسترسی به این متد را دارند.

اکشن متد برای پروفایل که مسئول مدیریت عملیات های GET است

در داخل این اکشن متد، یک View به عنوان خروجی فرستاده می شود. این اکشن متد دارای صفت [Authorize] است که به معنای این است که فقط کاربرانی که احرازهویت شده اند قابلیت دسترسی به این متد را دارند.

اکشن متد برای لاگین که مسئول مدیریت عملیات های POST است

در داخل این اکشن متد، متد ValidateUser فراخوانی می شود که  باعث می شود آن Stored Procedure که وظیفه تعیین اعتبار کاربر را داشت، اجرا شود.

وضعیت خروجی از این Stored Procedure دریافت می شود و اگر مقدار آن -1 بود به معنای آن است نام کاربری یا رمزعبور نادرست است و اگر مقدار آن -2 بود یعنی اطلاعات درست است ولی کاربر هنوزی فعال سازی اکانت را انجام نداده است و اگر مقدار دیگری بود به معنای صحت اطلاعات است و این اطلاعات در کوکی ذخیره می شود و کاربر به صفحه Profile فرستاده می شود. برای مقادیر -1 و -2 یک پیغام خطا به کاربر نمایش داده می شود.

اکشن متد برای Logout که مسئول مدیریت عملیات های POST است

در داخل این اکشن متد، متد Signout  از FormsAuthentication فراخوانی می شود که با این عمل تمامی اطلاعات مربوط به احراز هویت از کوکی پاک شده و کابر به صفحه Index منتقل می شود.

public class HomeController : Controller
{
    [AllowAnonymous]
    public ActionResult Index()
    {
        return View();
    }
 
    [Authorize]
    public ActionResult Profile()
    {
        return View();
    }
 
    [HttpPost]
    [AllowAnonymous]
    public ActionResult Index(User user)
    {
        UsersEntities usersEntities = new UsersEntities();
        int? userId = usersEntities.ValidateUser(user.Username, user.Password).FirstOrDefault();
 
        string message = string.Empty;
        switch (userId.Value)
        {
            case -1:
                message = "Username and/or password is incorrect.";
                break;
            case -2:
                message = "Account has not been activated.";
                break;
            default:
                FormsAuthentication.SetAuthCookie(user.Username, user.RememberMe);
                return RedirectToAction("Profile");
        }
 
        ViewBag.Message = message;
        return View(user);
    }
 
    [HttpPost]
    [Authorize]
    public ActionResult Logout()
    {
        FormsAuthentication.SignOut();
        return RedirectToAction("Index");
    }
}

View ها

Index

در داخل این View، در همان خط اول کلاس User Model به عنوان Model برای این View تعیین شده است.

این View دارای یک فرم Html است که به وسیله متد Html.BeginForm ساخته شده است و دارای پارامتر های زیر است.

ActionName – نام اکشن، در این مثال می شود همان Index

ControllerName – نام کنترلر که در این مثال می شود Home

FormMethod – مشخص کننده نوع متد است مثلا GET یا POST که در این مثال می شود POST

در داخل این View از 4 دستور HTML Helper که در پایین آمده اند استفاده شده است.

1-  Html.TextBoxFor- یک تکست باکس برای خصوصیت Model می سازد.

2-  Html.PasswordFor- یک تکست باکس مخصوص رمز عبور برای خصوصیت Model می سازد.

3- Html.ValidationMessageFor – نمایش پیام اعتبارسنجی برای خصوصیت های Model

4- . Html.CheckBoxFor- یک چک باکس برای خصوصیت Model می سازد.

همچنین یک کلید Submit وجود دارد که با کلیک بر روی آن محتویات فرم به شکل GET فرستاده می شود.

اسکریپت های jQuery و jQuery Validation در آخر به کمک تابع Scripts.Render به صفحه اضافه شده اند.

مقدار Message که در ViewBag است را ابتدا بررسی می کنیم که Null نباشد و اگر Null نبود، مقدار message را به کمک دستور جاوا اسکریپتی Alert نمایش می دهیم.

@model User_Login_MVC.User
 
@{
    Layout = null;
}
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width"/>
    <title>Index</title>
    <style type="text/css">
        body {
            font-family: Arial;
            font-size: 10pt;
        }
 
        table {
            border: 1px solid #ccc;
            border-collapse: collapse;
        }
 
        table th {
            background-color: #F7F7F7;
            color: #333;
            font-weight: bold;
        }
 
        table th, table td {
            padding: 5px;
            border: 1px solid #ccc;
        }
 
        .error {
            color: red;
        }
    </style>
</head>
<body>
    @using (Html.BeginForm("Index", "Home", FormMethod.Post))
    {
        <table border="0" cellpadding="0" cellspacing="0">
            <tr>
                <th colspan="3">
                    Login
                </th>
            </tr>
            <tr>
                <td>
                    Username
                </td>
                <td>
                    @Html.TextBoxFor(m => m.Username)
                </td>
                <td>
                    @Html.ValidationMessageFor(m => m.Username, "", new { @class = "error" })
                </td>
            </tr>
            <tr>
                <td>
                    Password
                </td>
                <td>
                    @Html.PasswordFor(m => m.Password)
                </td>
                <td>
                    @Html.ValidationMessageFor(m => m.Password, "", new { @class = "error" })
                </td>
            </tr>
            <tr>
                <td>
                    Remember Me
                </td>
                <td>
                    @Html.CheckBoxFor(m => m.RememberMe)
                </td>
                <td>
                   
                </td>
            </tr>
            <tr>
                <td></td>
                <td>
                    <input type="submit" value="Submit"/>
                </td>
                <td></td>
            </tr>
        </table>
    }
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/jqueryval")
    @if (@ViewBag.Message != null)
    {
        <script type="text/javascript">
            $(function () {
                alert("@ViewBag.Message")
            });
        </script>
    }
</body>
</html>

Profile

در داخل View مربوط به پروفایل، نام کاربری که لاگین کرده است را نمایش می دهد. همچنین یک لینک برای Logout در این صفحه قرار داده شده است.

وقتی که روی لینک Logout کلیک شود، فرم submit شده و اکشن متد Logout فراخوانی می شود.

@{
    Layout = null;
}
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width"/>
    <title>Profile</title>
    <title>Index</title>
    <style type="text/css">
        body {
            font-family: Arial;
            font-size: 10pt;
        }
    </style>
</head>
<body>
    <div>
        Welcome
        <b>@HttpContext.Current.User.Identity.Name</b>
        <br/>
        <br/>
        @using (Html.BeginForm("Logout", "Home", FormMethod.Post))
        {
            <a href="javascript:;" onclick="document.forms[0].submit();">Logout</a>
        }
    </div>
</body>
</html>

تنظیماتWeb.Config

شما باید قطعه کد زیر را به فایل Web.Config در بخش <system.web> اضافه کنید.

 <authentication mode="Forms">
      <forms defaultUrl="/Home/Profile" loginUrl="/Home/Index" slidingExpiration="true" timeout="2880"></forms>
</authentication>

خروجی

آموزش asp.net mvc

فایل های ضمیمه

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید