最近在學習用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源代碼小程序