最近看了一點 web api 2方面的書,對認證都是簡單介紹了下,因此我在這裏作個簡單Demo,本文主要是FORM Authentication,順帶把基本認證也講了。html
Demo前端
1、FORM Authenticationjquery
一、新建asp.net 空項目->Web API,以下圖所示:web
二、先建立一個簡單無認證示例:api
(1)、Models文件夾下新建Product類,跨域
/// <summary> /// 產品 /// </summary> public class Product { public int Id { get; set; } public string Name { get; set; } public string Category { get; set; } public decimal Price { get; set; } }
(2)、Controllers文件夾下新建ProductsController類,瀏覽器
public class ProductsController : ApiController { Product[] products = new Product[] { new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } }; public IEnumerable<Product> GetAll() { return products; } public IHttpActionResult Get(int id) { var product = products.FirstOrDefault((p) => p.Id == id); if (product == null) { return NotFound(); } return Ok(product); } }
(3)、建立index.html頁面,前端腳本以下, restful
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Web API2 Studt</title> </head> <body> <div> <h2>All Products</h2> <ul id="products"></ul> </div> <div> <h2>Search by ID</h2> <input type="text" id="prodId" size="5" /> <input type="button" value="Search" onclick="find();" /> <p id="product" /> </div> <script src="JS/jquery-2.0.3.min.js"></script> <script> var uri = 'api/products'; $(document).ready(function () { // Send an AJAX request $.getJSON(uri) .done(function (data) { // On success, 'data' contains a list of products. $.each(data, function (key, item) { // Add a list item for the product. $('<li>', { text: formatItem(item) }).appendTo($('#products')); }); }).fail(function (jqXHR, textStatus, err) { if (err == 'Forbidden') {self.location = 'login.html';} }); }); function formatItem(item) { return item.Name + ': $' + item.Price; } function find() { var id = $('#prodId').val(); $.getJSON(uri + '/' + id) .done(function (data) { $('#product').text(formatItem(data)); }) .fail(function (jqXHR, textStatus, err) { $('#product').text('Error: ' + err); }); } </script> </body> </html>
(4) index.html設爲起始頁,啓動後訪問成功,cookie
三、添加FORM Authentication認證, app
(1)、Controllers文件夾下新建FormAuth類,
using System; using System.Net; using System.Net.Http; using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; using System.Web.Security; namespace WebApi2Demo.Controllers { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class FormAuth : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { try { if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Count > 0) { base.OnActionExecuting(actionContext); return; } var cookie = actionContext.Request.Headers.GetCookies(); if (cookie == null || cookie.Count < 1) { actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden); return; } FormsAuthenticationTicket ticket = null; foreach (var perCookie in cookie[0].Cookies) { if (perCookie.Name == FormsAuthentication.FormsCookieName) { ticket = FormsAuthentication.Decrypt(perCookie.Value); break; } } if (ticket == null) { actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden); return; } // TODO: 添加其它驗證方法 base.OnActionExecuting(actionContext); } catch { actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden); } } } }
(2)、將FormAuth特性添加到ProductsController類上面,以下圖:
(3)、編譯網站後,刷新index.html頁面,跳轉到了login.html(須要新建)頁面,
看看前端js,
若是錯誤提示「Forbidden」,則跳轉到login.html頁面,這正是FormAuth中響應的HttpStatusCode(Forbidden = 403),
用Fiddler2看看,
(4)、添加登錄認證,
1)、 新建LogOn類,
public class LogOn { public string Username { get; set; } public string Password { get; set; } }
2)、新建登錄認證類,
public class AccountController : ApiController { [HttpPost] public HttpResponseMessage Post(LogOn model) { string password; if (model.Username == "zzhi") { if (model.Password == "12345") { FormsAuthentication.SetAuthCookie(model.Username, false); return Request.CreateResponse(HttpStatusCode.OK, "Success"); } return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Invalid username or password."); } else { return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Invalid username or password."); } } }
3)、login.html 腳本以下,
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>登錄</title> <script src="JS/jquery-2.0.3.min.js"></script> <script> var uri = 'api/Account'; function login() { var username = $("#username").val(); var password = $("#password").val(); $.post(uri, { Username: username, Password: password }) .success(function (result) { alert(result); window.location.href = "index.html"; }) .fail(function (XMLHttpRequest, textStatus, err) { alert(XMLHttpRequest.status); alert(XMLHttpRequest.text); alert(err); this.reload(); }); } </script> </head> <body> <label>用戶名</label><input id="username" type="text" /> <br /> <label>密 碼</label><input id="password" type="password" /> <br /> <button onclick="login()">登錄</button> </body> </html>
編譯網站後刷新login.html,輸入用戶名:zzhi,密碼:12345,提示登錄成功,而後跳轉到index.html頁面。
TEST:關閉網頁,再次啓動網站,直接進入index.html頁面並請求數據成功,fiddler2看看,
(5)、控制檯訪問API 2,代碼以下:
internal class Program { private static void Main(string[] args) { Process(); Console.Read(); } private static async void Process() { string token = GetSecurityToken("zzhi", "12345", "http://localhost:45690/api/Account", ".ASPXAUTH"); string address = "http://localhost:45690/api/products"; if (!string.IsNullOrEmpty(token)) { HttpClientHandler handler = new HttpClientHandler {CookieContainer = new CookieContainer()}; handler.CookieContainer.Add(new Uri(address), new Cookie(".ASPXAUTH", token)); using (HttpClient httpClient = new HttpClient(handler)) { HttpResponseMessage response = httpClient.GetAsync(address).Result; IEnumerable<Product> Products = await response.Content.ReadAsAsync<IEnumerable<Product>>(); foreach (Product c in Products) { Console.WriteLine(c.Name); } } } } private static string GetSecurityToken(string userName, string password, string url, string cookieName) { using (HttpClient httpClient = new HttpClient()) { Dictionary<string, string> credential = new Dictionary<string, string>(); credential.Add("Username", userName); credential.Add("Password", password); HttpResponseMessage response = httpClient.PostAsync(url, new FormUrlEncodedContent(credential)).Result; IEnumerable<string> cookies; if (response.Headers.TryGetValues("Set-Cookie", out cookies)) { string token = cookies.FirstOrDefault(value => value.StartsWith(cookieName)); if (null == token) { return null; } return token.Split(';')[0].Substring(cookieName.Length + 1); } return null; } } }
(6)、跨域訪問
1)、在web項目中(個人web項目名字:WebApi2Demo)經過Nuget添加 web api 2 corss-Origin 引用,以下圖:
2)、WebApiConfig.cs 配置以下:
var cors = new EnableCorsAttribute("*", "*", "*");//跨域訪問 config.EnableCors(cors); config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );
3)、ProductsController.cs 去掉[FormAuth]特性。
ASP.net裏面的Form認證,是經過在Cookie寫入登錄信息,而後瀏覽器發送請求後服務端再去驗證Cookie是否存在,從而達到認證用戶的目的。可是咱們如今涉及到一個跨域的問題,而Cookie是不能跨站共享的
。即便RESTful那邊設置了cookie,也不會到當前請求的域下面。到了第二次請求的時候,仍是得不到認證信息。
這裏我作了個簡單測試,若是你不註釋[FormAuth]特性,跨域是請求不到數據的。
那麼如何跨域認證呢,一種簡單方式是基本認證。
能夠經過Demo中的WebCorsTest項目進行測試。
2、基本認證,基本認證放在Demo中了,再也不贅述。
相關連接:RESTful api跨域認證
Api 2 資料:
ASP.NET Web API 2 Recipes_ A Problem-Solution Approach.pdf
ASP.NET Web API 2_ Building a REST Service from Start to Finish.pdf
Pro ASP.NET Web API HTTP Web Services in ASP.NET.pdf
好了到此結束。