Asp.net WebApi的授權安全機制 Basic認證

  • 2019 年 11 月 2 日
  • 筆記

1:Home/index.cshtml下面的Html程式碼

<div>          <input  value="1點擊先登陸" type="button" id="btnLogin"/><br />          <input value="2再點擊授權後調用介面" type="button" id="btnAuthenrazation" /><br />   </div>  

  

  

2:Home/index 下面的HomeController

[skipLogAttribute]  public ActionResult Index()  {  return View();  }

3: Ajax的模擬程式碼,先登錄,後獲取授權,再帶上Ticket,後台過濾器校驗ok雜可以請求對應的介面

<script type="text/javascript">  $(function () {  var ticket = "";  $("#btnLogin").click(function () { //---登陸的操作  $.ajax({  url: "http://localhost:8899/api/values",  data: { "uid": "zrf", "pwd": "123" },  type: "get",  success: function (res) {  if (res.result) {  ticket = res.ticket;  alert("授權成功"+res.ticket);  }  },  dataType:"json"  })  });    //----拿到了Ticket(後台過濾器會判斷是否有過授權,以及授權ok才可以調用對應的介面)  $("#btnAuthenrazation").click(function () {  $.ajax({  url: "http://localhost:8899/api/values",  data: { },  type: "get",  beforeSend: function (xhr) {  xhr.setRequestHeader('Authorization', 'BasicAuth ' + ticket);//--請求其他的介面都需要帶上Ticket的  },  success: function (res) {  alert("ok")  }  })  });  })    //帶上Ticket來訪問WebApi介面  $("#btnWithTicket").click(function () {  $.ajax({  url: "http://localhost:8899/api/values",  data: {"id":110},  type: "get",  beforeSend: function (xhr) {  xhr.setRequestHeader('Authorization', 'BasicAuth ' + ticket);//--請求其他的介面都需要帶上Ticket的  },  success: function (res) {  if (res.result) {  alert("調用成功" + res.data);  }  }  })  })  

  

  

4: 創建的一個測試的 WebApiController 如ValuesController:ApiController

namespace WebApplication1.Controllers  {  using System.Web.Security;  using WebApplication1.Filters;  public class ValuesController : ApiController  {    [HttpGet]  [skipLog]  public dynamic Login(string uid, string pwd)  {  dynamic result = null;  if ("zrf".Equals(uid) && pwd.Equals("123"))  {  FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, "account", DateTime.Now, DateTime.Now.AddSeconds(10), true, $"uid={uid},pwd={pwd}");  result = new { result = true, ticket = FormsAuthentication.Encrypt(ticket) };  }  else {  result = new { result = false, ticket = ""};  }  return result;  }  // GET api/<controller>  [skipLogAttribute]  public IEnumerable<string> Get()  {  return new string[] { "value1", "value2" };  }  // GET api/<controller>/5  [CustomerAuthenrazationFilter]  public dynamic Get(int id)  {  return new { result = true, id = id };  }  }  }  

 

5:授權過濾器:

using System;  using System.Collections.Generic;  using System.Linq;  using System.Web;    namespace WebApplication1.Filters  {      using System.Net.Http.Headers;      using System.Web.Http.Controllers;      using System.Web.Http.Filters;      using System.Web.Security;      using System.Web.Http;      using System.Net;        public class CustomerAuthenrazationFilterAttribute : AuthorizationFilterAttribute      {          public override void OnAuthorization(HttpActionContext actionContext)          {              skipLogAttribute skiplogin = actionContext.ActionDescriptor.GetCustomAttributes<skipLogAttribute>().FirstOrDefault();              if (skiplogin!=null)              {                  return;              }                AuthenticationHeaderValue headevalue = actionContext.Request.Headers.Authorization;              if (headevalue != null)              {                  string Msg = string.Empty;                  if (ValidateTicket(headevalue.Parameter,out Msg))                  {                      return;                  }                  else                  {                      this.HandlerUnAuthorization(Msg);                  }              }              else {                  this.HandlerUnAuthorization("請先獲取登陸授權的Ticket");              }          }          private void HandlerUnAuthorization(string Msg)          {              throw new Exception(Msg);          }            private bool ValidateTicket(string parameter,out string Msg)          {              Msg = string.Empty;              if (!string.IsNullOrWhiteSpace(parameter))              {                  FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(parameter);                  if (ticket != null)                  {                      if (ticket.Expired)                      {                          Msg = "介面時間已經過期,請重新登陸授權!";                          return false;                      }                      if (string.Equals($"uid=zrf,pwd=123", ticket.UserData))// $"uid={accountID},pwd={pwd}"                      {                          Msg = "授權成功!";                          return true;                      }                      else {                          Msg = "授權失敗,請重新登陸授權!";                          return false;                      }                  }              }              return false;          }      }  }  

  

 

6:自定義的特性,用來跳過許可權的驗證

using System;  using System.Collections.Generic;  using System.Linq;  using System.Web;    namespace WebApplication1.Filters  {  public class skipLogAttribute:Attribute  {  }  }  

  

 7:在WebApiConfig 文件中來註冊一個全局的授權過濾器

namespace WebApplication1.App_Start  {  using System.Web.Mvc;  public static class WebApiConfig  {  public static void Register(HttpConfiguration config)  {  // Web API 配置和服務    // Web API 路由  config.MapHttpAttributeRoutes();  config.Filters.Add(new Filters.CustomerAuthenrazationFilterAttribute());  }  }  }  

 

8:最後上兩張測試的截圖: 

 

 

 

 

 

 

最後,這個案例只是起到拋磚引玉的作用,大家還可以做得更加的細緻及合理

如下:

我們還可以加上隨機字元串:A;

時間戳:B(時間精確到秒,方便後續判斷,可過期);

唯一的uid C;

pwd D(根據uid來查詢資料庫並獲取到pwd),;

獲取自定義的簽名Sign:(如:uid+A+B+C+D 這4個值再MD5一下,防篡改),這樣就和微信那套機制就差不多了! 嘻嘻!

規則我們自己來定,歡迎大家提出有建議性的回復,謝謝