最近在学习用asp.net webapi搭建小程序的后台服务,由于基于小程序端和后台两者的通讯,不像OAuth(开放受权),存在第三方应用。因此这个token是双向的,一个是对用户的,一个是对接口的。原本作了一份是用Oauth的,用的是第三种密码策略模式。可是由于不存在第三方应用,因此不用Oauth这种受权标准。
这个Sample是用简单三层作的,书上得来终觉浅,绝知此事要躬行,实践一次就知道wepapi与前端如何经过token认证进行逻辑交互。html
为何会用MVC里用到的AuthorizationFilter呢,具体其实我当时不知道WebAPI里面能不能用,但由于领导说最好小程序访问进来,有一个统一验证的方法。由于我以前在另外一个项目里建立了一个控件器基类,BaseController,用于作登陆验证,权限验证,日志记录,以及公共方法。由于用了OnActionExecuting,因此当时想也没有想,直接搜索Web API OnActionExecuting,看到Web API也有Filter的相关资料。最后参考了[Web APi之认证(Authentication)]((https://www.cnblogs.com/CreateMyself/p/4857799.html),从而顺利完成了这个双向token认证逻辑。 首先,在Controllers文件夹里建立AuthFilterAttribute,即自定义Filter特性。这个class里面先重写OnAuthorization方法。 /// <summary> /// 最早运行的Filter,被用做请求权限校验 /// </summary> public class AuthFilterAttribute : AuthorizationFilterAttribute { public override void OnAuthorization(HttpActionContext actionContext) {} }
Web APi之认证(Authentication)两种实现方式【二】(十三)前端
OnAuthorization是重写的。那么具体应该写什么呢?固然是进行验证当前的请求是否有受权,是不是 符合要求的请求报文头。 public override void OnAuthorization(HttpActionContext actionContext) { //若是用户方位的Action带有AllowAnonymousAttribute,则不进行受权验证 if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any()) { return; } string authParameter = null; var authValue = actionContext.Request.Headers.Authorization;//actionContext:Action方法请求上下文 if (authValue != null && authValue.Scheme == "BasicAuth")//这里有BasicAuth和参考资产里面的不一样,咱们没有认定类,这里的BasicAuth就算是咱们自定义的token规则。其实主要是我尚未了解认证身份以及了解GenericIdentity。 { authParameter = authValue.Parameter; //获取请求参数 var authToken = authParameter.Split('|'); //取出参数,参数格式为(当前时间:加密后的token)将其进行分割 Logging.Error(authParameter); if (authToken.Length < 2) { actionContext.Response = new HttpResponseMessage(HttpStatusCode.NotAcceptable);//参数不完整,返回406不接受 } else { //参数完整,进行验证 if (ValidateToken(authToken[0],authToken[1])) { base.OnAuthorization(actionContext); } else { actionContext.Response = new HttpResponseMessage(HttpStatusCode.ExpectationFailed);//验证不经过,未知足指望值417 } } } else { //若是验证不经过,则返回401错误,而且Body中写入错误缘由 actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, new HttpError("Token 不正确")); } }
//验证token public bool ValidateToken(string loginTime,string token) { bool flag = true; DateTime checkTime = DateTime.Parse(loginTime); //先验证时间是否过时 DateTime nowtime = DateTime.Now; TimeSpan a = nowtime - checkTime; Logging.Error("a:"+ a.TotalSeconds); if (a.TotalSeconds > 120)//时间过时 { flag = false; } else { string checkToken = Utils.GetTokenString(loginTime); Logging.Error("1:"+checkToken+";2:"+token); //比较token if (token.Equals(checkToken, StringComparison.CurrentCultureIgnoreCase)) { flag = true; } else { flag = false; } } return flag; }
[HttpGet] [Authorize] [Route("Test")] //public string Test() public WxResponseResultModel Test() { WxResponseResultModel rsEntity = new WxResponseResultModel(); rsEntity.Code = "200"; rsEntity.Message = "这是后台传的测试方法"; //return "这是后台传的测试方法"; return rsEntity; }
var keyStr = '123456'; var timestamp = getMyFormatDate(new Date(),'yyyy-MM-dd hh:mm:ss');//获取当前时间 console.log("timestamp:" + timestamp); var token = hexMD5(keyStr + timestamp); console.log("token:" + token); var apiServiceBaseUri = "http://localhost:52545/"; $(function () { var data = {code:"25"}; $.ajax({ beforeSend: function (xhr) { xhr.setRequestHeader('Authorization', 'BasicAuth ' + timestamp+"|"+token);//token规则 }, url: apiServiceBaseUri + 'Login/Test', type: "GET", dataType: 'json', success: function (data) { alert(data.Message); //alert(Message); } }); });
首先测试没有[Authorize]的时候,由于最早执行的就是AuthorizationFilter,因此毫无悬念会进入OnAuthorization()进行验证。
git
其次,在Test这个Action添加[Authorize]看看,这里会有一个疑问,明明是应该认证的方法,添加了[Authorize]属性,更加应该进入OnAuthorization()才对,为何会拒绝认证呢?
github
这是由于是配置文件中,配置了全局过滤器。 //注册全局Filter config.Filters.Add(new AuthFilterAttribute()); 把[Authorize]换成配置的[AuthFilter]属性,就能够成功访问了。
因为小程序对ajax这一块进行了封装,请求统一使用 wx.request请求,使用wx.request加入报文报求的时候,不像ajax这样,写在beforeSend里面。wx.request是写在header里面。token规则在app.js里面作了全局变量调用。 wx.request({ url: app.globalData.api + 'Login/Test', method: "GET", header: { 'Authorization': app.globalData.header, 'content-type': 'application/json', }, // 设置请求的 header success: function (res) { //若是是对象的话,写法为 console.log(res.data.Message); // console.log(res.data); }, fail:function(res){ console.log("fail:" + res) } });
测试期间出现一个bug,提示以下:
未能找到 CodeDom 提供程序类型“Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf385
web
解决办法参考:
未能找到 CodeDom 提供程序类型ajax
参考资料:
api token参考资料
api接口token验证
小程序登陆逻辑参考资料
ASP.NET WebApi做服务端开发小程序实现微信受权用户登陆实例——登陆逻辑1
ASP.NET WebApi做服务端开发小程序实现微信受权用户登陆实例——登陆逻辑2
ASP.NET WebApi做服务端开发小程序实现微信受权用户登陆实例——登陆逻辑3
json
本文WebAPI源代码小程序