最近在學習用asp.net webapi搭建小程序的后台服務,因為基於小程序端和后台二者的通信,不像OAuth(開放授權),存在第三方應用。所以這個token是雙向的,一個是對用戶的,一個是對接口的。本來做了一份是用Oauth的,用的是第三種密碼策略模式。但是因為不存在第三方應用,所以不用Oauth這種授權標准。
這個Sample是用簡單三層做的,書上得來終覺淺,絕知此事要躬行,實踐一次就知道wepapi與前端如何通過token認證進行邏輯交互。
搭建項目
- 搭建項目這一點不多說,直接新建一個空的,

用AuthorizationFilter篩選器完成授權
為什么會用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)兩種實現方式【二】(十三)
token規則以及解析請求報文頭
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驗證
//驗證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;
}
測試請求授權
- 新建一個Contorller,添加一個名為Test的Action進行測試
[HttpGet]
[Authorize]
[Route("Test")]
//public string Test()
public WxResponseResultModel Test()
{
WxResponseResultModel rsEntity = new WxResponseResultModel();
rsEntity.Code = "200";
rsEntity.Message = "這是后台傳的測試方法";
//return "這是后台傳的測試方法";
return rsEntity;
}
- 前端頁面請墳,在本機新建html頁面進行測試,token使用了MD5加密方式。
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()進行驗證。


其次,在Test這個Action添加[Authorize]看看,這里會有一個疑問,明明是應該認證的方法,添加了[Authorize]屬性,更加應該進入OnAuthorization()才對,為什么會拒絕認證呢?


這是因為是配置文件中,配置了全局過濾器。
//注冊全局Filter
config.Filters.Add(new AuthFilterAttribute());
把[Authorize]換成配置的[AuthFilter]屬性,就可以成功訪問了。
發布IIS,聯合小程序測試
由於小程序對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

解決辦法參考:
未能找到 CodeDom 提供程序類型
參考資料:
api token參考資料
api接口token驗證
小程序登錄邏輯參考資料
ASP.NET WebApi作服務端開發小程序實現微信授權用戶登錄實例——登錄邏輯1
ASP.NET WebApi作服務端開發小程序實現微信授權用戶登錄實例——登錄邏輯2
ASP.NET WebApi作服務端開發小程序實現微信授權用戶登錄實例——登錄邏輯3
