zoukankan      html  css  js  c++  java
  • 转:ajax的AntiForgery和Authorize 以及ajax登录例子

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    本文链接:https://blog.csdn.net/ashcn2001/article/details/53409256
    现有的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);
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    或者这里有令外一个替代方法用来备选,本质上是一样的 (备选)

    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);
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    使用方法为
    客户端 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);
    }
    });


    })
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    服务器端则可以使用
    因为是在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();
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    如何对登陆信息进行验证呢,这里可以使用

    针对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");
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    客户端cshtml的使用

    $(function()
    {
    $(document).ajaxError(function(e, xhr) {
    if (xhr.status == 403)
    {
    var response = $.parseJSON(xhr.responseText);
    window.location = response.LogOnUrl;
    }
    });
    });
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    服务器端的使用
    在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(登录失败了!);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    综合演示
    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>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    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; }
    }
    }
    ————————————————
    版权声明:本文为CSDN博主「ashcn2001」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/ashcn2001/article/details/53409256

  • 相关阅读:
    C#面试题
    C# 安装部署
    Ribbon菜单栏布局和调整大小
    Dev GridControl使用小结
    C#多线程学习(一) 多线程的相关概念
    PDF转换成图片——11种方案
    C#多线程学习(二) 如何操纵一个线程
    C# 截屏方式
    dev中gridview控件
    (转载) 如何降低project压缩文件的大小? (Quartus II)
  • 原文地址:https://www.cnblogs.com/dragon2017/p/11718769.html
Copyright © 2011-2022 走看看