转: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 ></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