c# WebApi之身份驗證:Basic基礎認證


為什么需要身份認證

身份認證是為了提高接口訪問的安全性,如果沒有身份驗證,那么任何匿名用戶只要知道服務器的url,就可以隨意訪問服務器,從而訪問或者操作數據庫,這會是很恐怖的事。

什么是Basic基礎認證

Basic基礎認證是一種簡單的用戶名、密碼驗證過程,它的主要原理是加密用戶信息,生成票據,每次需要身份驗證時將票據帶過來驗證,實現步驟為:

  1. 用戶登錄,登錄成功后將生成的票據返回到前端;
  2. 前端登錄成功后,收到票據信息,跳轉到主頁面,並且吧票據一並帶過去,存入Session;
  3. 在需要請求頁面,把票據信息加入到請求的Head里面,將票據信息隨着請求一起發送到服務端去;
  4. 在WebApi服務里面定義一個類,繼承AuthorizeAttribute類,然后重寫父類的OnAuthorization方法,在OnAuthorization方法里面取到當前http請求的Head,從Head里面取到我們前端傳過來的票據信息。解密票據信息,從解密的信息里面得到用戶名和密碼,然后驗證用戶名和密碼是否正確。如果正確,表示驗證通過,否則返回自定義錯誤信息。

Basic基礎認證的代碼示例:

首先新建兩個項目:Web測試站點、WebApi站點 
這里寫圖片描述

1.1、在Web測試站點,添加一個登錄頁面:

<div style="text-align:center;"> <div>用戶名:<input type="text" id="txt_username" /></div> <div>密 碼:<input type="password" id="txt_password" /></div> <div><input type="button" value="登錄" id="btn_login" class="btn-default" /></div> </div>

登錄請求的ajax:

 $(function () { $("#btn_login").click(function () { $.ajax({ type: "get", url: "http://localhost:61593/api/account/login", data: { strUser: $("#txt_username").val(), strPwd: $("#txt_password").val() }, success: function (data, status) { if (status == "success") { if (!data.bRes) { alert("登錄失敗"); return; } alert("登錄成功"); //登錄成功之后將用戶名和用戶票據帶到主界面 window.location = "/Home/Index?UserName=" + data.UserName + "&Ticket=" + data.Ticket; } }, error: function (e) { }, complete: function () { } }); }); });

1.2、對應的WebApi站點的,登錄的Api接口:

/// <summary> /// 用戶登錄 /// </summary> /// <param name="strUser"></param> /// <param name="strPwd"></param> /// <returns></returns> [HttpGet] public object Login(string strUser, string strPwd) { if (!ValidateUser(strUser, strPwd)) { return new { bRes = false }; } FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(0, strUser, DateTime.Now, DateTime.Now.AddHours(1), true, string.Format("{0}&{1}", strUser, strPwd), FormsAuthentication.FormsCookiePath); //返回登錄結果、用戶信息、用戶驗證票據信息 var oUser = new UserInfo { bRes = true, UserName = strUser, Password = strPwd, Ticket = FormsAuthentication.Encrypt(ticket) }; //將身份信息保存在session中,驗證當前請求是否是有效請求 HttpContext.Current.Session[strUser] = oUser; return oUser; } //校驗用戶名密碼(正式環境中應該是數據庫校驗) private bool ValidateUser(string strUser, string strPwd) { if (strUser == "admin" && strPwd == "123456") { return true; } else { return false; } }

自定義UserInfo實體:

public class UserInfo { public bool bRes { get; set; } public string UserName { get; set; } public string Password { get; set; } public string Ticket { get; set; } }

新建的WebApi需要配置一下路由,打開App_Start文件夾下的WebApiConfig.cs文件,添加一條路由信息:

public static void Register(HttpConfiguration config) { //解決跨域訪問問題 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi1", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); }

如果是兩個站點的話可能會出現跨域問題,解決跨域訪問問題可以參考: 
http://blog.csdn.net/lwpoor123/article/details/78457589

2.1、在Web測試站點添加一個用於跳轉測試的index主頁面

<html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <script src="~/Scripts/jquery-1.10.2.min.js"></script> </head> <body> 測試結果: <div id="div_test"> hello world </div> 當前登錄用戶: <div id="username"> @ViewBag.UserName </div> </body> </html>

ajax請求:

<script> var ApiUrl = "http://localhost:61593/"; $(function () { $.ajax({ type: "get", url: ApiUrl + "api/Account/GetAllData", data: {}, beforeSend:function(XHR){ XHR.setRequestHeader('Authorization','BasicAuth @ViewBag.Ticket') }, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } }, error: function (e) { $("#div_test").html("Error"); } }); }); </script>

這里需要注意在beforeSend方法里面,向請求的報文頭里面增加票據信息,用於把Ticket信息一同帶到服務器: 
XHR.setRequestHeader(‘Authorization’,’BasicAuth @ViewBag.Ticket’) 
這里寫圖片描述

2.2、index頁面的action,接收傳遞過來的票據數據,存入Session

public ActionResult Index(string UserName, string Ticket) { if (UserName != null) { Session["UserName"] = UserName; } if (Ticket != null) { Session["Ticket"] = Ticket; } ViewBag.UserName = Session["UserName"]; ViewBag.Ticket = Session["Ticket"]; return View(); }

2.3、對應的Api接口:

public class AccountController : ApiController { /// <summary> /// 得到所有數據 /// </summary> /// <returns>返回數據</returns> [HttpGet] [RequestAuthorize] public string GetAllData() { return "Success"; } }

WebAip默認是沒有開啟Session,需要手動開啟: 
在WebApi站點,打開Global.asax文件,重寫Init()方法

public override void Init() { this.PostAuthenticateRequest += (sender, e) => HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required); base.Init(); }

或者:

public override void Init() { PostAuthenticateRequest += MvcApplication_PostAuthenticateRequest; base.Init(); } void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e) { HttpContext.Current.SetSessionStateBehavior( SessionStateBehavior.Required); }

3.1、WebApi身份驗證部分(重點) 
在WebApi站點,添加一個RequestAuthorizeAttribute.cs文件,繼承AuthorizeAttribute,自定義此特性用於接口的身份驗證:

 /// <summary> /// 自定義此特性用於接口的身份驗證 /// </summary> 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<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>(); bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute); if (isAnonymous) base.OnAuthorization(actionContext); else HandleUnauthorizedRequest(actionContext); } } protected override void HandleUnauthorizedRequest(HttpActionContext actioncontext) { base.HandleUnauthorizedRequest(actioncontext); var response = actioncontext.Response = actioncontext.Response ?? new HttpResponseMessage(); response.StatusCode = HttpStatusCode.Forbidden; var content = new { code = -1, success = false, errs = new[] { "服務端拒絕訪問:你沒有權限,或者掉線了" } }; response.Content = new StringContent(Json.Encode(content), Encoding.UTF8, "application/json"); } //校驗用戶名密碼(正式環境中應該是數據庫校驗) 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; } } }

3.2、使用的時候只需要在控制器前面加上自定義的身份驗證[RequestAuthorize]

/// <summary> /// 得到所有數據 /// </summary> /// <returns>返回數據</returns> [HttpGet] [RequestAuthorize] public string GetAllData() { return "Success"; }

這里寫圖片描述

這里寫圖片描述

這里寫圖片描述

如果不攜帶票據或者票據無效,服務端拒絕訪問: 
這里寫圖片描述

如果在控制器加了身份驗證,有些請求又不想使用驗證,可以在方法上面添加特性標注[AllowAnonymous]

[RequestAuthorize]
public class AccountController : ApiController { /// <summary> /// 得到所有數據 /// </summary> /// <returns>返回數據</returns> [HttpGet] public string GetAllData() { return "Success"; } [AllowAnonymous] public string getData() { return "data"; } }
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM