来源:赖的安分
链接:http://www.cnblogs.com/landeanfen/p/5287064.html
我们看到,上面的/Home/Index页面里面发送了ajax请求去访问服务的 http://localhost:27221/api/Charging/GetAllChargingData 这个接口,那么我们在WebApi里面怎么去验证这个请求和合法的请求呢?接下来我们重点看看验证的这个过程。
///
/// 自定义此特性用于接口的身份验证
///
public class RequestAuthorizeAttribute : AuthorizeAttribute
{
//重写基类的验证方式,加入我们自定义的Ticket验证
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
//从http请求的头里面获取身份验证信息,验证是否是请求发起方的ticket
var authorization = actionContext.Request.Headers.Authorization;
if ((authorization != null) & (authorization.Parameter != null))
{
//解密用户ticket,并校验用户名密码是否匹配
var encryptTicket = authorization.Parameter;
if (ValidateTicket(encryptTicket))
{
base.IsAuthorized(actionContext);
}
else
{
HandleUnauthorizedRequest(actionContext);
}
}
//如果取不到身份验证信息,并且不允许匿名访问,则返回未验证401
else
{
var attributes = actionContext.ActionDescriptor.GetCustomAttributes().OfType();
bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute);
if (isAnonymous) base.OnAuthorization(actionContext);
else HandleUnauthorizedRequest(actionContext);
}
}
//校验用户名密码(正式环境中应该是数据库校验)
private bool ValidateTicket(string encryptTicket)
{
//解密Ticket
var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData;
//从Ticket里面获取用户名和密码
var index = strTicket.IndexOf('&');
string strUser = strTicket.Substring(0, index);
string strPwd = strTicket.Substring(index + 1);
if (strUser == 'admin' & strPwd == '123456')
{
return true;
}
else
{
return false;
}
}
}
[RequestAuthorize]
public class ChargingController : ApiController
{
///
/// 得到所有数据
///
/// 返回数据
[HttpGet]
public string GetAllChargingData()
{
return 'Success';
}
///
/// 得到当前Id的所有数据
///
/// 参数Id
/// 返回数据
[HttpGet]
public string GetAllChargingData(string id)
{
return 'ChargingData' + id;
}
}
增加了特性标注之后,每次请求这个API里面的接口之前,程序会先进入到我们override过的 OnAuthorization() 方法里面,验证通过之后,才会进到相应的方法里面去执行,否则返回401。
通过上面的几步,基本就能达到我们想要的身份认证的效果,但是总是感觉不太方便,主要不太方便的点有以下几个。
每次新建一个API,对应的接口上面都要标注 [RequestAuthorize] 这个一个东西,感觉好麻烦。
每次发送ajax请求,都要在beforeSend事件里面加 XHR.setRequestHeader(‘Authorization’, ‘BasicAuth ‘ + Ticket); 这个,感觉也麻烦。
如果有些WebApi服务的某些方法,我们不想使用这个验证,让它可以匿名用户验证(比如我们的登录方法Login)。该怎么处理呢。
关于以上两点,我们优化下
在API里面加一个公共的父类,在父类上面标注 [RequestAuthorize] 即可。
namespace WebApiCORS.Controllers
{
[RequestAuthorize]
[EnableCors(origins: '*', headers: '*', methods: '*')]
public class BaseApiController : ApiController
{
}
}
namespace WebApiCORS.Controllers
{
public class ChargingController : BaseApiController
{
///
/// 得到所有数据
///
/// 返回数据
[HttpGet]
public string GetAllChargingData()
{
return 'Success';
}
///
/// 得到当前Id的所有数据
///
/// 参数Id
/// 返回数据
[HttpGet]
public string GetAllChargingData(string id)
{
return 'ChargingData' + id;
}
}
}
注意:我们登录的请求是不需要验证的,因为登录的时候还没有产生票据,所以登录的API不能够继承 BaseApiController
还记得我们在 JS组件系列——封装自己的JS组件,你也可以 这篇里面介绍的增加ajax的error事件的公共处理方法吗?我们是否也可以通过同样的机制去增加这个呢。新建一个文件Jquery_ajax_extention.js
(function ($) {
//1.得到$.ajax的对象
var _ajax = $.ajax;
$.ajax = function (options) {
//2.每次调用发送ajax请求的时候定义默认的error处理方法
var fn = {
error: function (XMLHttpRequest, textStatus, errorThrown) {
toastr.error(XMLHttpRequest.responseText, '错误消息', { closeButton: true, timeOut: 0, positionClass: 'toast-top-full-width' });
},
success: function (data, textStatus) { },
beforeSend: function (XHR) { },
complete: function (XHR, TS) { }
}
//3.扩展原生的$.ajax方法,返回最新的参数
var _options = $.extend({}, {
error: function (XMLHttpRequest, textStatus, errorThrown) {
fn.error(XMLHttpRequest, textStatus, errorThrown);
},
success: function (data, textStatus) {
fn.success(data, textStatus);
},
beforeSend: function (XHR) {
XHR.setRequestHeader('Authorization', 'BasicAuth ' + Ticket);
fn.beforeSend(XHR);
},
complete: function (XHR, TS) {
fn.complete(XHR, TS);
}
}, options);
//4.将最新的参数传回ajax对象
_ajax(_options);
};
})(jQuery);
引用这个js后再发送ajax不必在每个请求的beforeSend里面写了。
如果我们某些方法不想使用验证,使得它可以让匿名用户访问,我们可以在方法的上面加特性标注 [AllowAnonymous] ,申明该方法运行匿名访问。比如:
public class ChargingController : BaseApiController
{
///
/// 得到所有数据
///
///
返回数据 [HttpGet]
public string GetAllChargingData()
{
return 'Success';
}
///
/// 得到当前Id的所有数据
///
/// 参数Id
///
返回数据 [HttpGet]
[AllowAnonymous]
public string GetAllChargingData(string id)
{
return 'ChargingData' + id;
}
}
以上结合一个实例讲解了下Basic认证的实现原理以及简单使用,本文观点都是来自博主自己的理解。
联系客服