ajax的AntiForgery和Authorize 以及ajax登录例子

11 篇文章 0 订阅
6 篇文章 0 订阅

现有的mvc无法用无刷的形式来对数据进行验证 特别是对于ajax 进行数据访问,如果是机密信息则有很大的风险。现在可以用自定义attribute的方法来加入针对数据信息验证。

针对AntiForgery的验证方法

attrbute属性的定义

    [AttributeUsage(AttributeTargets.Class)]
    public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
        {
            public override void OnAuthorization(AuthorizationContext filterContext)
            {
                var request = filterContext.HttpContext.Request;

            //  Only validate POSTs
            if (request.HttpMethod == WebRequestMethods.Http.Post)
            {
                //  Ajax POSTs and normal form posts have to be treated differently when it comes
                //  to validating the AntiForgeryToken
                if (request.IsAjaxRequest())
                {
                    var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                    var cookieValue = antiForgeryCookie != null
                        ? antiForgeryCookie.Value
                        : null;

                    try {

                        AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
                    }
                    catch (Exception e) { 
                    //filterContext.Result = new RedirectResult("/Account/Login?returnUrl=" +
                    // HttpUtility.UrlEncode(filterContext.HttpContext.Request.Url.ToString()));

                    ContentResult result = new ContentResult();
                    result.Content = "<div style='text-align:center;padding:1em;' >当前已经处于退出状态,请重新登录</div>";
                    filterContext.Result = result;

                    }
                }
                else
                {
                    new ValidateAntiForgeryTokenAttribute()
                        .OnAuthorization(filterContext);
                }
            }
            else {
                throw new Exception("没有权限");
                //base.HandleUnauthorizedRequest(filterContext);
            }
            }
    }

或者这里有令外一个替代方法用来备选,本质上是一样的 (备选)

    public class ExtendedValidateAntiForgeryToken : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            var request = filterContext.HttpContext.Request;
            if (request.HttpMethod != WebRequestMethods.Http.Post) return;
            if (request.IsAjaxRequest())
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];
                var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null;
                //从cookies 和 Headers 中 验证防伪标记  
                //这里可以加try-catch  
                    try {

                        AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
                    }
                    catch (Exception e) { 
                    //filterContext.Result = new RedirectResult("/Account/Login?returnUrl=" +
                    // HttpUtility.UrlEncode(filterContext.HttpContext.Request.Url.ToString()));

                    ContentResult result = new ContentResult();
                    result.Content = "<div style='text-align:center;padding:1em;' >当前已经处于退出状态,请重新登录</div>";
                    filterContext.Result = result;

                    }
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute().OnAuthorization(filterContext);
            }
        }
    }

使用方法为
客户端 cshtml里面需要用js来发送post数据到服务器。

 //获取防伪标记
    var token = $('@Html.AntiForgeryToken()').val();
    @*var token = $("[name='__RequestVerificationToken']").val();*@
        var headers = {};
        //防伪标记放入headers
        //也可以将防伪标记放入data
        headers["__RequestVerificationToken"] = token;
        $(document).on("click", ".nav-tabs a", function (e) {

            if ($(this).parent().parent().hasClass("nav")) {
                $(".nav-tabs li").removeClass("active");
                $(this).parent().addClass("active");
            }
           e.preventDefault();
            //alert($(this).attr("href"));
        $.ajax({
            type: 'POST',
            url: $(this).attr("href"),
            cache: false,
            headers: headers,
            data: {},
            beforeSend: function () {
                $("#myTabContent").html("正在索取数据");
            },

            success: function (data) {
                //alert(data)
                $("#myTabContent").html(data);
            },
            error: function (data) {
                $("#myTabContent").html(data);
            }
        });


    })

服务器端则可以使用
因为是在class上使用的属性 所以

 [HealthCareCore.ValidateAntiForgeryTokenOnAllPosts]
 public class AJAXController : Controller
 {
    public ActionResult Order(string tabName)
        {
            IQueryable<nongfuEntityframework.Info> quene = db.Info;
            Regex reg = new Regex(@"page=.{1,}?(&|$)");//获取page的页数 
            var url = reg.Replace(Request.QueryString.ToString(), "");
            switch (tabName)
            {
                case "allOrder":
                      return PartialView("Order_tab", quene);
                case "notPaid":
                    quene= quene.Where(m => m.pay_status == 0);
                    return PartialView("Order_tab", quene);
            }
            return View();
        }
   }

如何对登陆信息进行验证呢,这里可以使用

针对Authorize的验证方法

attribute属性的定义

 public class AjaxAuthorizeAttribute : AuthorizeAttribute
    {
        protected override void HandleUnauthorizedRequest(AuthorizationContext context)
        {
            if (context.HttpContext.Request.IsAjaxRequest())
            {
                var urlHelper = new UrlHelper(context.RequestContext);
                context.HttpContext.Response.StatusCode = 403;
                context.Result = new JsonResult
                {
                    Data = new
                    {
                        Error = "NotAuthorized",
                        LogOnUrl = urlHelper.Action("LogOn", "Account")
                    },
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };
            }
            else
            {
                base.HandleUnauthorizedRequest(context);
                //throw new Exception("No enough right");
            }
        }
    }

客户端cshtml的使用

  $(function()
    {
        $(document).ajaxError(function(e, xhr) {
            if (xhr.status == 403)
            {
                var response = $.parseJSON(xhr.responseText);
                window.location = response.LogOnUrl;
            }
        });
    });

服务器端的使用
在action上面加上[AjaxAuthorize]

服务器上ajax登录

在mvc当中我们使用jquery的ajax向服务器发送登录信息捎带手当然我们必须使用ValidateAntiForgeryToken来做方位认证,当然这里还有个问题,那就是我们用ajax所发出的数据是透明的,实际上在截获的发送数据中我们的用户名和密码都是明文的

使用ajax登录的技术为
ajax发送数据(带有用户名密码和forgerytoken)->
服务器进行登录,mvc内置的登陆中回想response写入登录cookie->
ajax接收相关登录成功信息,并自动从返回的信息中把cookie写到客户端

[HttpPost]
[ExtendedValidateAntiForgeryToken]
public ActionResult Login(LoginInfo model){
    if(登录成功){
         var httpCookie = System.Web.HttpContext.Current.Response.Cookies[key];
         if (httpCookie == null) return;
        httpCookie.Value = value;
        httpCookie.Expires = expires;
        return Json(登录成功!);
    }else{
        return Json(登录失败了!);
    }
}

综合演示
cshtml端

<!DOCTYPE html>
@{ 
    Layout = null;
}
<html>
<head>
    <title>Ajax Login</title>
</head>
<body>
   username: @ViewBag.username
    <div class="container">
        <form id="login-form" action="#" method="POST">
            @*生成防伪标记*@
            @Html.AntiForgeryToken()
            <div class="controls">
                <label for="userName">用户名:</label>
                <input type="text" name="userName" id="userName" placeholder="用户名" value="@ViewBag.UserName" />
            </div>
            <div class="controls">
                <label for="password">密 码:</label>
                <input type="password" name="password" id="password" placeholder="密码" />
            </div>
            <div class="controls">
                <input type="checkbox" name="rememberMe" id="rememberMe" />
                <label for="rememberMe">记住我?</label>
            </div>
            <input type="submit" value="登录" class="btn" />
        </form>
    </div>
    <script src="~/Scripts/jquery-1.10.2.js"></script>
    <script src="~/Scripts/jquery.validate.js"></script>

</body>
</html>  
<script>

        $("#login-form").validate({
            rules: {
                userName: {
                    required: true,
                },
                password: {
                    required: true,
                    rangelength: [8, 20]
                }
            },
            messages: {
                userName: "请输入用户名!",
                password: {
                    required: "请输入密码!",
                    rangelength: "请输入{0}到{1}之间的密码!"
                }
            }, submitHandler: function (form) {
                //获取防伪标记
                var token = $('input[name=__RequestVerificationToken]').val();
                var headers = {};
                headers["__RequestVerificationToken"] = token;
                var params = $(form).serialize();
                $.ajax({
                    type: "POST",
                    url: "Login",
                    data: params,
                    headers: headers,
                    success: function (result) {
                        alert(result.msg);
                    },
                    error: function () {
                        alert("Error");
                    }
                });
            }
        });
</script>  

accountcontroller.cs

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Net;  
using System.Web.Helpers;  
using System.Web.Mvc;  
using MvcAjaxDemo.Models;  

namespace MvcAjaxDemo.Controllers
{
    public class AccountController : Controller
    {
        //  
        // GET: /Account/Login  
        public ActionResult Login()
        {
            ViewBag.UserName = Retrieve("UserName");

            return View();
        }

        [HttpPost]
        [ExtendedValidateAntiForgeryToken]
        public ActionResult Login(LoginInfo model)
        {
            //是否为Ajax请求  
            if (!Request.IsAjaxRequest())
                return View();
            if (model.UserName == null)
                return Json(GetResult(false, "用户名为空!", null));
            //根据用户名获取用户  
            var user = UserService.GetUsers().SingleOrDefault(p => p.LoginName == model.UserName);

            if (user == null)
                return Json(GetResult(false, "用户名或密码错误!", null));
            //验证密码  
            if (user.Password != model.Password)
                return Json(GetResult(false, "用户名或密码错误!", null));

            if (!string.IsNullOrWhiteSpace(model.RememberMe))
            {
                //保存帐户登录名  
                Save("UserName", model.UserName, DateTime.Now.AddDays(2));
            }

            return Json(GetResult(false, "登录成功!", null));

        }

        #region 辅助方法  
        /// <summary>  
        /// 获取结果集  
        /// </summary>  
        /// <param name="rel">状态</param>  
        /// <param name="msg">提示信息</param>  
        /// <param name="data">数据集</param>  
        /// <returns></returns>  
        public static object GetResult(bool rel, string msg, object data)
        {
            return new Dictionary<string, object> { { "rel", rel }, { "msg", msg }, { "obj", data } };
        }

        /// <summary>  
        /// 保存Cookie  
        /// </summary>  
        /// <param name="key"></param>  
        /// <param name="value"></param>  
        /// <param name="expires">过期时间</param>  
        public void Save(string key, string value, DateTime expires)
        {
            var httpCookie = System.Web.HttpContext.Current.Response.Cookies[key];
            if (httpCookie == null) return;
            httpCookie.Value = value;
            httpCookie.Expires = expires;
        }
        /// <summary>  
        /// 检索Cookie  
        /// </summary>  
        /// <param name="key"></param>  
        /// <returns></returns>  
        public string Retrieve(string key)
        {
            var cookie = System.Web.HttpContext.Current.Request.Cookies[key];
            return cookie != null ? cookie.Value : "";
        }
        #endregion
    }


    #region 防止CSRF攻击特性  
    /// <summary>  
    /// 防止CSRF攻击特性  
    /// </summary>  
    public class ExtendedValidateAntiForgeryToken : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            var request = filterContext.HttpContext.Request;
            if (request.HttpMethod != WebRequestMethods.Http.Post) return;
            if (request.IsAjaxRequest())
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];
                var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null;
                //从cookies 和 Headers 中 验证防伪标记  
                //这里可以加try-catch  
                AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute().OnAuthorization(filterContext);
            }
        }
    }
    #endregion

    //Model  
    public class User
    {
        public int Id { get; set; }
        public string LoginName { get; set; }
        public string Password { get; set; }
    }


    public class UserService
    {
        public static IList<User> GetUsers()
        {
            return new List<User>
            {
                new User
                {
                    Id=1,
                    LoginName = "admin",
                    Password = "admin1234"
                }
            };
        }
    }
}
namespace MvcAjaxDemo.Models
{
    public class LoginInfo
    {
        /// <summary>  
        /// 用户名  
        /// </summary>  
        public string UserName { get; set; }
        /// <summary>  
        /// 密码  
        /// </summary>  
        public string Password { get; set; }
        /// <summary>  
        /// 记住我?  
        /// </summary>  
        public string RememberMe { get; set; }
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值