GR7,我不能說我曾經嘗試自己在做什麼。
讓我指出一些令你煩惱的事情,以及我認爲你可以使它工作的事情。
您在一個Web服務器上運行ASP.NET MVC應用程序,並在另一個服務器上運行ASP.NET WebAPI應用程序。你想從另一個使用cookie。來自MVC應用程序的cookie如何對WebAPI應用程序有效?即使用戶的用戶名和密碼在兩個系統上都是相同的,那麼由兩個不同應用程序生成的cookie會不會相同呢?只是要清楚,我不是100%確定的,這只是一個懷疑。
這是我懷疑的基礎 - 假設您在Azure雲上運行ASP.NET MVC應用程序,並且它具有負載平衡(意味着您實際上有多個實例,每個實例在不同的物理機上運行) 。用戶連接到您的網站,並在該實例上進行身份驗證。然後,他導航到該網站上的另一個頁面,負載平衡器最終將他發送到另一個實例的該頁面。我相信在這種情況下他將被要求重新進行身份驗證,因爲他的cookie無效,即使它是完全相同的MVC應用程序。解決這種情況的方法是在所有機器上設置相同的機器密鑰。
這是MSDN上這裏討論: http://msdn.microsoft.com/en-us/library/eb0zx8fc(v=vs.100).aspx
和一個Microsoft知識庫文章: http://support.microsoft.com/kb/910443
也有一些StackOverflow上的文章討論這個: Does Forms Authentication work with Web Load Balancers?和 .NET Forms Authentication in Azure - What changes are required for multiple VMs?
所以我猜您應該可以將機器密鑰設置爲在兩臺Web服務器上都相同,然後將Cookie從MVC應用程序傳遞到We bAPI應用程序爲了不使用戶驗證兩次。希望有人會糾正我,如果我錯了。
另一種解決方案是堅持兩個cookie,一個用於MVC應用程序,另一個用於Web API。你需要弄清楚在哪裏存儲webapi cookie - 因爲ASP.NET以無狀態的方式工作,每次用戶點擊不同的MVC頁面時,這基本上是一個全新的事務。所以也許你想要用戶瀏覽器存儲這兩個cookie。第一次進行身份驗證時,您將使用相同的用戶名和密碼在MVC應用程序和WebAPI應用程序上對其進行身份驗證,然後將這兩個cookie都發回給他(當然,MVC cookie會自動返回給他)。因此,每當他導航到不同的頁面時,您都會將Cookie發送到您的MVC應用程序,並且必須接收其中的一個並使用它調用WebAPI應用程序。您可能需要確保兩個cookie不具有相同的名稱(默認情況下,這兩個都將是ASPXAUTH)。您可以使用在web.config中改變你的MVC cookie的名稱
<authentication mode="Forms">
<forms name="MyAuthCookie" loginUrl="LoginPage.aspx" />
</authentication>
這應該允許你存儲在用戶的瀏覽器2塊餅乾,還可以幫助你區分它們。我假設您的MVC和WebAPI都在同一個域中,否則瀏覽器將不會接受WebAPI cookie(或至少在後續請求中不會將它傳回給您)。
如果這個答案幫助,請投,我幾乎沒有任何代表:)
=========================== ===========
編輯 - 在回答下面的問題時添加以下內容 - 您想知道如何實際獲取WebAPI提供給您的MVC應用程序的Cookie,並將其返回給用戶的瀏覽器。我將從您的mvc應用程序發送帶有您的憑證的http post請求到您的webapi,讓您清楚所有事情。
讓我們使用JSON將登錄信息作爲HTTP請求的一部分從您的MVC應用程序發送到Web API服務器。木箱在你的MVC應用程序的模型文件夾中的模型是這樣的:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace SitterWebsite.Models
{
public class MyJsonLoginModel
{
public string UserName;
public string Password;
public bool RememberMe;
}
}
然後在您登錄()在ActionController.cs方法,您可以添加這樣的事情做出要求
string loginapibaseaddress = "http://mywebapiurl.com/";
string loginapiaddress = "api/AccountAPI/SignMeIn";
MyJsonLoginModel mydatamodel = new MyJsonLoginModel()
{
UserName = "gary",
Password = "password",
RememberMe = false,
};
// Create the JSON formatter.
MediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();
// Use the JSON formatter to create the content of the request body.
HttpContent content = new ObjectContent<MyJsonLoginModel>(mydatamodel, jsonFormatter);
// I am going to return the cookie received from the Web API controller to the browser
// I will obtain it from the HTTP POST request to the WebAPI in the form of a Cookie object
// I will then need to convert it to an HttpCookie object
Cookie cookietosendback = new Cookie(); // cookie of type System.Net.Cookie
HttpCookie httpcookietosendback = new HttpCookie("will_name_later"); // cookie of type System.Web.HttpCookie
// Create a new cookie container.
// We will attach this cookie container to the HTTP request
// The Web API auth cookie will automatically be put into this container
CookieContainer cookie_container = new CookieContainer();
HttpClientHandler handler = new HttpClientHandler();
handler.CookieContainer = cookie_container;
HttpClient loginclient = new HttpClient(handler);
// Set the base address of the client
loginclient.BaseAddress = new Uri(loginapibaseaddress);
// Set the web api address of the client
Uri loginapiaddressuri = new Uri(loginapibaseaddress+loginapiaddress);
// Send an HTTP POST request
HttpResponseMessage response = loginclient.PostAsync(loginapiaddressuri, content).Result;
Cookie mycookie;
if (response.IsSuccessStatusCode)
{
// Now let's access the cookies from the cookie container since it will be automatically populated with any
// cookies returned by our http request (ie. any cookies in the http response).
IEnumerable<Cookie> responseCookies = cookie_container.GetCookies(loginapiaddressuri).Cast<Cookie>();
foreach (Cookie cookie in responseCookies)
{
if cookie.Name.Equals('.ASPXAUTH')
cookietosendback = cookie
}
// We want to return the cookie to the users browser
// However the HttpContext.Response.Cookies.Add() method needs an HttpCookie object, not a Cookie object
// So we need to convert the Cookie to an HttpCookie
httpcookietosendback.Name = "GaryCookie"; // changing name since both MVC and WebAPI name their cookie .ASPXAUTH
httpcookietosendback.Value = cookietosendback.Value;
httpcookietosendback.Path = cookietosendback.Path;
httpcookietosendback.Expires = cookietosendback.Expires;
httpcookietosendback.Domain = cookietosendback.Domain;
// Note - if the domain of your WebAPI is different from the MVC app, you might want to change it in
// above statement, otherwise the browser will either not accept a cookie from another domain, or it will
// definitely not pass it to the mvc app in your next request
this.ControllerContext.HttpContext.Response.Cookies.Add(httpcookietosendback);
}
else
{
// Http post to webapi failed
}
所以,現在當你進入登錄頁面並輸入你的憑證並點擊提交時,你不僅會得到你通常得到的MVC cookie,還會獲得WebAPI cookie。它將按照我上面的代碼命名爲「GaryCookie」。每次你到你網站上的另一個頁面,你的瀏覽器都會請求該頁面,並將這兩個cookie發送到你的mvc應用程序。如果你想調用其他的WebAPI方法,你現在需要做與我剛剛做的相反的事情,也就是說將修改後的WebAPI cookie「GaryCoookie」並重新命名爲原來的內容。然後在您的WebAPI方法上發出GET或POST請求時將其與標題一起發送。
如果您的webapi和mvc應用程序不在同一個域中,您還應該設置cookie的域以匹配MVC的域。否則,如果您請求另一個頁面,您的瀏覽器將不會將cookie發送到MVC應用程序。
順便說一下,我剛剛測試了所有這些,所以它的工作原理。
嗨加里,感謝您的答覆。我沒有說我想爲這兩個系統使用同一個cookie,我說我的想法是,當用戶登錄到MVC網站時,在LogOn操作上,我可以以純文本訪問用戶名和密碼,哪一點我想我可以用相同的憑據進行webapi調用以獲得webapi auth cookie,然後使用該cookie用於任何進一步的webapi調用。你有沒有做過? – GR7 2013-05-09 16:14:07
GR7,謝謝澄清。你所說的是正確的。這基本上就是我在迴應的第二部分(以「另一個解決方案......」開頭)所說的。當您的用戶登錄到MVC網站時,您將能夠訪問用戶名和密碼。假設您使用表單身份驗證和爲您生成的默認C#代碼。如果您查看AccountController.cs,您會看到登錄操作。 public ActionResult Login(LoginModel model,string returnUrl){ } – Gary 2013-05-09 20:37:50
在該方法中,您可以使用model.UserName和model.Password訪問用戶名和密碼。然後,您應該能夠調用WebAPI並從中獲取身份驗證Cookie。 – Gary 2013-05-09 20:38:34