本文轉自:http://www.cnblogs.com/wanliwang01/p/aspnet_webapi_base01.htmljavascript
ASP.NET MVC和WebAPI已是.NET Web部分的主流,剛開始時兩個公用同一個管道,以後爲了更加的輕量化(WebAPI是對WCF Restful的輕量化),WebAPI使用了新的管道,所以二者相關類的命名空間有細微差別,在使用時須要注意。 html
WebAPI學習系列目錄以下,歡迎您的閱讀!java
快速入門系列--WebAPI--01基礎jquery
快速入門系列--WebAPI--04在老版本MVC4下的調整算法
ASP.NET MVC的路由:Routes(RouteCollection)的線程安全,讀寫鎖,GetReadLock, GetWriteLock。RouteTable.Routes.MapPageRoute(…); 編程
命名空間爲System.Web.Routing中json
WebAPI的路由:首先介紹其相關類型,他們均是對Http報文的簡易封裝,System.Net.Http(HttpRequestMessage, HttpResponseMessage)。 windows
命名空間爲System.Web.Http.Routing中
HttpRouteHandler。
還記的ASP.NET MVC中的核心是HttpHandler,而在WebAPI中其管道處理器是HttpMessageHandler。在實際中其經過職責鏈模式將委託經過InnerHandler(DelegationHandler)方式進行處理。其中,其中這個管道最開始的是httpServer,最末端的是HttpRoutingDispatcher(均在System.Web.Http命名空間下,支持異步模型),P108
Tip:額外想一想也能理解WebAPI管道爲何更加輕量化,於是它只須要處理Json等類型數據,不須要考慮如頁面、JS、靜態資源等內容。
Class: [RoutePrefix("api/demo")],針對具體類的路由設置,相對RouteConfig,粒度更細。
Method: [Route("action")]
[HttpGet], [HttpPost]
關於Web服務,其中比較難的概念通常都集中在安全,其相關概念很是的多,包括Windows相關認證模式、Forms認證、第三方認證、跨域訪問等,接下來一一介紹。此外還會附加HttpClient、IOC框架的選擇、服務冪等性、SignalR、EntLib中的EHAB等概念。
.NET安全模型:
Identiy表示用戶身份, Identity AuthenticationType, IsAuthenticated, Name},常見的Identity有WindowsIdentity, FormsIdentity, GenericIdentity。P556
IPrincipal, 被成功實施受權的實體,等價於身份加角色,包括WindowsPrincipal(windows的權限組),GenericPrincipal, RolePrincipal(Membership組件和Roles組件) 。常見的認證方式經過"質詢-應答"(challenge-Response)方式。
常見http認證方式,Basic和Digest,前者使用將認證憑證(用戶名+密碼)經過base64編碼而未加密,但咱們可使用https傳輸來解決機密性問題。與此相關的兩個過濾器, AuthenticationFilter和AuthorizationFilter。
補充ActionFilter概念,好比請求涉及大量運算,而且輸入和輸出一一對應(即相同的輸入有相同的輸出),那麼能夠考慮緩存Action。P585
Windows認證模式(均經過在IIS中設置身份認證模式)
WebHost寄宿下的安全:Windows認證模式,經過Basic, Digest認證方案,最終採用NTLM或者Kerberos協議。認證用戶的Principal體如今HttpContext、當前線程、ApiControlelr。Keep-Alive,Fidder查看調用。
名稱 | 狀態 | 響應類型 |
Active Directory客戶端證書身份驗證 | 已禁用 | HTTP 401 質詢 |
ASP.NET 模式 | 已禁用 | |
Forms身份驗證 | 已禁用 | HTTP 302 登陸/重定向 |
Windows身份驗證 | 已禁用 | HTTP 401 質詢 |
基自己份驗證(Windows/Basic) | 已禁用 | HTTP 401 質詢 |
匿名身份驗證 | 已禁用 | |
摘要式身份驗證(Windows/digest) | 已啓用 | HTTP 401 質詢 |
如今都是HTTP401 質詢模型,只有forms是http 302 登陸/重定向。這個關於basic的質詢方式頗有意思,就是當你請求時,出現http 401,會要求你輸入用戶名密碼,輸入後你輸入的用戶名和密碼會被base64編碼發送的服務器,形式是Basic YWRtaW46YWRtaW4=,這部分的head就是authentication。查看windows的憑據管理器,帳號密碼木有問題,但仍然不能經過驗證,很是的傷感,本身試着加上域cn1\,結果OK了,感受棒棒噠,哈哈,說明asp.net安全模型和windows有很好的整合性。
Basic模式的流程是,瀏覽器向服務器IIS以匿名的方式發送GET請求,IIS回覆一個401 Unauthorized的響應,該響應用"www-authenticate"報頭告訴客戶端採用的認證方案(basic)和對應的領域(Realm, localhost)。瀏覽器收到響應彈出登陸對話框,收集輸入的帳號密碼組成字符串做爲認證憑證,接下來,瀏覽器再次發送請求,在authorization包頭中攜帶認證的方案和用戶的憑證Basic YWRtaW46YWRtaW4=,IIS解密後認證,action順利執行。
Base64:是網絡常見的用於傳輸8bit字節代碼的編碼方式,用在http表單(包括隱藏的表單域)和http GET url中,base64編碼的信息具備不可讀性,但不具備機密性,使用時須要注意應用場景。
Digest認證僅僅適用於Domain模式,若是基於WorkGroup模式,也沒法使用,接下來經過fiddler看看相應的HTTP消息頭。
HTTP 401的響應:
WWW-Authenticate: Digest qop="auth",algorithm=MD5-sess,nonce="+Upgraded+v1e4fcae181b935afc3d94f30f5033141a25e3c7e4b83bd101c60cf10ea425a352c8959c8d47e643e5fc38f90cffe411be5f7a99033900ae4d",charset=utf-8,realm="Digest"
Digest認證傳輸用戶憑證的哈希碼,而不是明文。客戶端首先匿名向服務器發送GET請求,服務器返回一個401響應,這個響應包含一個"WWW-Authenticate"報頭,攜帶的信息包括。
參數 | 解釋 |
Digest | 認證方案 |
Realm="Digest" | 領域 |
Algorithm | 表示服務端支持的哈希算法,MD5-sess |
Nonce | 服務端生成的惟一性標示,通常來講,IIS會利用當前時間戳以及請求的Etag(被請求變量的實體值)報頭值來生成這個nonce |
Qop(Quanlity of Protection) | IIS採用qop通知客戶端採用的消息保護等級,可選值包括auth(authentication), auth-int(authentication-integrity),前者僅限於基本的認證,後者還確保傳輸內容的一致性。 |
輸入帳號密碼的再一次請求(響應爲200成功):
Authorization: Digest username="cn1\\she_s", realm="Digest", nonce="+Upgraded+v1e4fcae181b935afc3d94f30f5033141a25e3c7e4b83bd101c60cf10ea425a352c8959c8d47e643e5fc38f90cffe411be5f7a99033900ae4d", uri="/Sory.Entertainment.WebAPI/", algorithm=MD5-sess, response="9a6cb99fad4404cdd521e5db432f6b09", qop="auth", nc=00000001, cnonce="c77c05d93544b363"
其相關參數爲:
參數 | 解釋 |
Username | 表明客戶端的用戶名,看來用戶名仍是能夠截取的 |
Qop | 最終採用的消息保護等級, qop="auth" |
Algorithm | 最終採用的加密算法,MD5-sess |
Nonce | 實際就是服務器端生成的nonce |
cnonce | 客戶端生成的nonce(c表明client),它能夠對請求內容簽名以確保內容未被篡改,能夠幫助客戶端對服務端實施認證(服務端可以證實知道該nonce,這些很適合防護跨站請求僞造的防護) |
Nc(nonce count) | 它表示客戶端針對同一個nonce發送請求的數量,一位着這是隨着請求不斷增長的數字,IIS能夠經過nc表明的數字來防止"重放攻擊",它會維護每一個nonce的nc,若是請求攜帶的nc比這個少,會被認爲是不合法的請求。 |
IIS在接受到第二次請求後,它先對請求進行合法性校驗(好比nc的合法性),而後從Authentication報頭提取用戶名、nonce和加密算法計算出針對用戶名真正的Digest,最終利用它與請求中提供的Digest進行比較確認密碼的正確性,完成客戶端認證。
Tip:
<script type="application/json" id="__browserLink_initializationData">
{"appName":"Firefox","requestId":"ee1fc1d3f30e4b4cba937703bee3ce10"}
</script>
<script type="text/javascript" src="http://localhost:13820/69ea419b05a141aaa5111affa4bb02fe/browserLink" async="async"></script>
這部分如何理解,與jsonP相關?
不管問basic仍是Digest認證,若是使用瀏覽器作客戶端,第一次訪問總須要在彈出框中輸入,很是繁瑣,而且密碼在網絡中傳輸,有安全風險,通常採用加鹽的方式避免。集成Windows認證能夠很好解決該問題,它默認以登陸機器的Windows帳號的名義來訪問被受權的資源沒,用戶的密碼被包含在請求攜帶的安全令牌中,很是的方便,該方式最終使用NTLM和Kerberos協議來完成。
NTLM協議(比較陳舊):採用質詢/應答(Challenge/Response)消息交換模式,DC域控制器保存所用用戶的相關信息。基本流程爲:步驟1,用戶輸入帳戶密碼登陸主機,主機會緩存輸入密碼的哈希值,原始密碼會丟失。若是視圖訪問服務器資源,須要向對方發送請求,請求中包含一個明文表示的用戶名;步驟2,服務端接受請求,生成16位隨機數(稱爲質詢challenge),存儲起來後以明文的形式發送給客戶端;和Digest請求中nonce的意圖徹底一致;步驟3,客戶端收到服務端的質詢後,用在步驟1中保存的密碼哈希值對其加密,而後將加密後的質詢發送給服務端;步驟4,服務端收到加密質詢後,會向DC發送針對客戶端的驗證請求(請求中包括,用戶名、客戶端密碼加密後的質詢和原始的質詢);步驟五、6,DC根據用戶名得到密碼哈希值,對原始質詢加密,再與服務端發送的質詢比較,一致就爲驗證經過,不然失敗。
Kerberos:這東西也算是困擾了小弟不少年,老看到,尤爲每次註冊windows時,呵呵,你懂得。實際上它是一種更搞笑安全的認證協議,過程更加的複雜,與NTLM類似,也包含三部分,客戶端、服務器和KDC(Key Distribution Center,在windows域中,KDC有DC擔當)。Kerberos實際是一種基於票據(Ticket)的認證方式,客戶端要訪問服務端的資源,首先要購買服務端承認的票據。也就是說,客戶端在訪問服務器前要先買好票,等待服務器驗票後才能入場,但這票不能直接購買,首先須要認購權證(和糧票,股票認購權證類似)。這個認購權證和進入服務器的入場券均由KDC發售,感受各類繞……相關詳細內容暫時放一放。
在IIS中使用windows集成驗證時,會看到provider的設置,有"negotiate"和"NTLM"兩個選項,默認使用前者,其Provider包括"Negotiate: Kerberos",固然也能夠自定義。此外,客戶端須要在IE設置-》高級中,開啓Windows集成認證,默認是開啓的。在使用HttpClient時,可使用如下方式,簡化調用。
1 HttpClientHandler handler = new HttpClientHanlder(); 2 方式1: Handler.UseDefaultCredentials = true; 3 方式2: handler.Credentials = new NetworkCredentials("username", "password", "domainname"); 4 Using(HttpClient client = new HttpClient(handler)){}
可與獨立於windows系統的認證方式,之前作webform時,forms認證是用的最多的,當時還一直覺得forms驗證也須要和windows相關,尤爲是和webForm中的form相關,如今想一想挺幼稚的,同時這個驗證能夠和membership很好的搭配在一塊兒。但實際上這種驗證方式是獨立的,適合自行維護用戶帳號和密碼的場景,也是絕大部分項目的場景。那麼接下來介紹forms認證是如何進行的,努力使本身真正的走出誤區。
Forms認證的流程設計4次的消息交換,其具體步驟以下所示。
步驟1:用戶經過瀏覽器匿名向IIS發起請求,假設地址爲"/home",它會收到狀態爲"302, Found"的相應,這是一個用於實現"重定向"的http響應,它經過location報頭表示的重定向地址指向登陸的頁面,以前訪問的地址將做爲查詢字符串returnURL的值。
步驟2:瀏覽器接受到該請求後,針對重定向的地址發送請求,登陸頁面最終被呈如今瀏覽器。
步驟3:用戶輸入正確的用戶名密碼後提交表單,服務器在接受到請求以後提取它們對用戶實施認證,認證成功後,它會生成一個安全令牌或者認證票據。接下來,經過查詢字符串returnURL表示的原始請求地址,做爲另外一個狀態爲"302, Found"響應的Location報頭,而通過加密/簽名的安全令牌做爲該響應的Cookie。
步驟4:這個表明安全令牌的Cookie將自動附加到瀏覽器後續的請求中,服務器直接利用它對請求實施認證。Cookie的名稱、過時策略以及採用的保護等級都可以經過配置來控制。在禁用Cookie的狀況下,安全令牌會直接做爲URL的一部分傳送。
Tip:
首先想補充補充的是原來的forms認證的配置經過以下配置,加上在login相關方法上加上[AllowAnonymous],而後IIS中設置啓用匿名認證和forms認證便可。
1 <authentication mode="Forms" > 2 <forms loginUrl="~/account/login"/> 3 </authentication> 4 <authorization> 5 <deny users="?"/> 6 </authorization>
在ASP.NET 5以後的版本配置方式有一些變化,爲了和第三方認證OAuth集成,不須要配置文件的配置,而是經過以下代碼配置,若是添加每每會出錯。
1 app.UseCookieAuthentication(new CookieAuthenticationOptions 2 { 3 AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 4 LoginPath = new PathString("/Account/Login") 5 });
Cookie採用的保護等級,在IE設置中包括6個隱私等級,對cookie的管理程度各不相同,從cookie徹底不可讀寫,到徹底可讀寫,默認的等級爲中,阻止沒有精簡隱私策略的第三方cookie。
昨天和同事聊天時,還注意到有的項目的logoff是直接跳轉頁面,而不是action,所以缺乏清空session等服務器端信息的操做,在實際開發中也算是個易錯點。
以前介紹的認證方式,都要求密碼(token)在網絡中進行傳輸,爲了確保密碼不被竊取,須要用SSL\TLS對傳輸的內容實施保護。其中涉及不少安全相關的基礎知識點,這兒只作簡要介紹。
Tip:對於數字證書想說的是,必定要把它才分開了理解,大致包含三部分,公鑰信息、簽名信息和其餘信息。而且後面二者都是爲前者的安全送達服務的,簡而言之(如12306購買火車票場景,祝願你們都能買到過個幸福年,哈哈),網站經過要求用戶安裝根證書的方式將網站通訊密鑰對中的公鑰發送給我,但爲了保證這個過程的安全,就須要提供數字簽名的過程。就像將情報通信密碼給我,而且簽上了FBI同樣,以後就能夠用這個密碼進行通信了。這個說的比較粗略,有些簡化,省略了認證權威機構和認證樹的概念。
關於SSL/TLS的概念,後者TLS(Transport Layer Security)實際上是前者SSL(Secure Sockets Layer)的升級版本,TLS1.0就是SSL3.1,在IE的設置中,能夠看到默認支持SSL 3.0和TLS1.0。而HTTPS是指HTTP與SSL/TLS的結合,像以前介紹的12306的安全,就是https的,也稱爲弱安全模型,那麼強安全模型是什麼?那就是咱們使用網銀時,你們都經歷安裝安全控件甚至使用U盾的過程,這兒就是強安全。簡單來講,強安全,指服務器端和客戶端都要安裝對方的證書,相互認證;弱安全,指客戶端安裝服務器證書,客戶端認證服務器。接下來介紹請求Https網站的過程。
步驟1:客戶端向https站點發送協商請求,包括客戶端所支持的加密算法列表
步驟2:Https站點從算法列表中選擇所能支持最合適安全級別的算法(安全性和效率折衷),連同綁定到該站點的數字證書一併發送給客戶端。
步驟3:客戶端接受證書後,經過驗證確認站點身份,成功後,生成一個隨機數,做爲會話密鑰(Session key)緩存在客戶端。客戶端採用發回的加密算法,利用證書中的公鑰對該密鑰(Session Key)加密,加密後發送給站點,站點解密得到Session key。
步驟4:客戶端和服務端使用該Session key使用對稱加密算法進行加解密。(對稱加密效率高,但密鑰管理難,所以採用結合二者的方式,用非對稱加密管理密鑰,用密鑰來對稱加密,棒棒噠)
IIS對多種傳輸協議提供支持,包括http、Tcph和MSMQ等,站點綁定數字證書的方式喲不少,最方便的是用iis管理器,其步驟以下。
步驟1:在未目標站點添加https綁定以前,咱們須要爲它準備一張證書,能夠用makeCert.exe工具,也可使用iis管理器來建立自我簽名的證書。在IIS的特性列表中選擇"服務器證書",以後選擇"建立自我簽名證書",命名和站點名稱相同便可。
步驟2:在IIS中,選擇咱們指定的站點(Web Site),右鍵選擇編輯綁定,在網站綁定頁面添加https類型並選擇相應的證書,在瀏覽網站欄就能夠看到http, 和https了。這時你就能夠瀏覽網頁經過兩種不一樣的方式,固然你自定義的證書未被加入根證書,所以用https時,瀏覽器會顯示一個小紅叉。以後在httpclient部分,你也會發現,咱們能夠經過設置,跳過客戶端對服務器證書的驗證,方便調用,不過不推薦。
網站的常見調用能夠經過http和https兩種方式,但具體到某一個調用的時候,須要在"安全"和"性能"間權衡,可是認證過程必須採用https,將指定的action設置爲[RequireHttps],那麼它就只能經過https協議訪問到。該特性實際是MVC提供的一個AuthenticationFilter,若是是一個普通請求,則會把該請求重定向到https的相應地址。這兒你們會注意到一個問題就是requiredHttps是MVC下的概念,那麼WebAPI中有對應概念麼?這個能夠經過自定義的認證過濾器來處理。
1 public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext) 2 { 3 //若是爲https請求,受權經過 4 if (Uri.UriSchemeHttps == actionContext.Request.RequestUri.Scheme) 5 { 6 base.OnAuthorization(actionContext); 7 return; 8 } 9 10 //對於http-get請求,將schema替換成https進行重定向 11 if (HttpMethod.Get == actionContext.Request.Method) 12 { 13 var requestUri = actionContext.Request.RequestUri; 14 string location = string.Format("https://{0}/{1}", requestUri.Host, requestUri.LocalPath.TrimStart('/')); 15 var actionResult = new RedirectResult(new Uri(location), actionContext.Request); 16 actionContext.Response = actionResult.ExecuteAsync(new CancellationToken()).Result; 17 } 18 19 //採用其餘http方法的請求直接認爲是bad request 20 actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest) { ReasonPhrase = "SSL Required" }; 21 }
通常來講,web應用的用戶認證均由自身完成,經過存儲用戶名和密碼並進行驗證,但這種方式在當前的互聯網場景下會有一下兩個主要問題:用戶須要註冊不一樣的帳號,記住和使用很是的麻煩了;對於應用提供者,大量認證系統會花費大量的精力。基於OAuth2.0(Open Authentication 2.0)的第三方認證模型的出現正好能夠解決這個痛點,該模型藉助了Google, 微信等值得信賴的IT服務提供商。OAuth是定義一種協議幫助資源的擁有者在不提供自身憑證的前提下受權第三方應用以他的名義存儲保護的資源。
得到資源擁有者受權的第三方應用獲取受保護的資源採用的不是受權者憑證,而是一個被稱爲Access Token的安全令牌,Access Token頒發過程會涉及若干不一樣的角色。接下來經過一個蔣大師提到的簡單例子作相應的介紹。例如咱們開發了一個集成了新浪微博認證用於發佈打折商品信息的App,通過用戶受權以後它能夠調用新浪微博的WebAPI獲取用戶的電子郵箱地址併發布相應的打折消息。那麼OAuth在該場景下的做用是,用戶受權該應用以本身名義調用新浪微博的webAPI獲取本身的郵箱地址,涉及4個角色:資源擁有者,通常爲最終用戶;客戶端應用,須要得到資源擁有者受權並最終訪問受保護資源的應用;資源服務器,最終承載資源的服務器,一本爲一個webAPI;受權服務器,它對用戶和客戶端實施認證,並在用戶受權的狀況下向客戶端應用頒發Access Token,在以前介紹的場景下,二者合一,均爲新浪微博。
通常來講,若是須要針對某個第三方認證服務來開發應用,須要向對應的認證服務提供商對應用進行註冊,成功後得到AppID/AppSecet(名稱不必定同樣),實際工做中其實每一個項目每每也有AppID。常見的,咱們能夠申請windows服務https://account.live.com/developers/applications/, 申請應用後能夠獲取clientID和clientSecret,而且設置重定向的域名。這兒想提醒你們的一點,就是這個重定向設置能夠是多個,而且必定要和你每個請求的重定向設置對應起來,一旦沒有設置,windows live會報沒法提供服務的錯誤。
這兒流程相似於Kerberos認證,首先客戶端獲取受權憑證,以後再購買訪問憑證,最後訪問資源。Authorization grant(縮寫AG)包含4中類型:Implicit,省略了獲取AG過程;Authorization Code, 標準模式,這個AG是一個受權碼;以後的兩種不太有價值,就不介紹了。
該模型中,經過獲取當前請求的AccessToken,以後調用Windows Live Connect提供的API(https://apis.live.net/v5.0/me)。不過在此以前,若是用戶未登錄到Windows Live,那麼首先會跳轉到登錄頁面,完成GetProfile調用後將json格式字符串顯示在瀏覽器中。這兒的核心是,咱們經過AuthenticateAttribute將AccessToken寫入Cookie中,這與Forms認證類似,不過從安全角度講,利用Cookie攜帶安全令牌會引發被稱爲"跨站請求僞造CSRF, Cross-Site Request Forgery"的安全問題,因此用htto報頭來做爲安全令牌的載體比較合理。在IAuthenticationFilter接口的ChallengeAsync用於在認證過程當中向客戶端發送"質詢"響應,若是AccessToken不存在,就像WindowLive受權頁面重定向,參數(response-type, redirect_uri, client, scope)以查詢字符串形式提供。而IActionFilter中的方法ExecuteActionFilterAsync用於將AccessToken寫入cookie。代碼以下所示:
1 public class DemoController : ApiController 2 { 3 public HttpResponseMessage GetProfile() 4 { 5 string accessToken; 6 if (this.Request.TryGetAccessToken(out accessToken)) 7 { 8 using (var client = new HttpClient()) 9 { 10 string address = string.Format("https://apis.live.net/v5.0/me?access_token={0}", accessToken); 11 return client.GetAsync(address).Result; 12 } 13 } 14 return new HttpResponseMessage(HttpStatusCode.BadRequest) { ReasonPhrase = "No access token" }; 15 } 16 17 public class AccountController : Controller 18 { 19 [RequireHttps] 20 public ActionResult CaptureToken(string requestUri) 21 { 22 ViewBag.RequestUri = requestUri; 23 return View(); 24 } 25 26 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] 27 public class AuthenticateAttribute : FilterAttribute, IAuthenticationFilter, IActionFilter 28 { 29 public const string CookieName = "AccessToken"; 30 public string CaptureTokenUri { get; private set; } 31 public AuthenticateAttribute(string captureTokenUri) 32 { 33 this.CaptureTokenUri = captureTokenUri; 34 } 35 36 public Task AuthenticateAsync(HttpAuthenticationContext context, System.Threading.CancellationToken cancellationToken) 37 { 38 return Task.FromResult<object>(null); 39 } 40 41 public Task ChallengeAsync(HttpAuthenticationChallengeContext context, System.Threading.CancellationToken cancellationToken) 42 { 43 string accessToken; 44 if (!context.Request.TryGetAccessToken(out accessToken)) 45 { 46 string clientId = "00000000441745E6"; 47 string redirectUri = string.Format("{0}?requestUri={1}", this.CaptureTokenUri, context.Request.RequestUri); 48 string scope = "wl.signin%20wl.basic"; 49 50 var uri = new StringBuilder(); 51 uri.Append("https://login.live.com/oauth20_authorize.srf"); 52 uri.Append("?response_type=token"); 53 uri.AppendFormat("&redirect_uri={0}&client_id={1}&scope={2}", redirectUri, clientId, scope); 54 55 context.Result = new RedirectResult(new Uri(uri.ToString()), context.Request); 56 } 57 return Task.FromResult<object>(null); 58 } 59 60 public Task<System.Net.Http.HttpResponseMessage> ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation) 61 { 62 var response = continuation().Result; 63 string accessToken; 64 if (actionContext.Request.TryGetAccessToken(out accessToken)) 65 { 66 response.SetAccessToken(actionContext.Request, accessToken); 67 } 68 return Task.FromResult<HttpResponseMessage>(response); 69 } 70 71 CaptureToken.cshtml 72 <html> 73 <head> 74 <title></title> 75 <script src="@Url.Content("~/scripts/jquery-1.10.2.js")"></script> 76 <script type="text/javascript"> 77 $(document).ready(function () { 78 var redirectUri = '@ViewBag.RequestUri'; 79 if (redirectUri.indexOf(