1

我正在建立一個網站,將有一個MVC端,並將從我們自己的WebAPI後端獲取其數據,但很可能託管在不同的服務器上(甚至在Azure上) 。我們將使用Forms身份驗證。MVC到相同的應用程序的WebAPI身份驗證

因爲我們希望用戶只需要登錄一次(到MVC網站),推薦的方式是透明地認證WebAPI後端的用戶以及他們在MVC表單上輸入的相同信息的身份驗證登錄?

由於此認證基於cookie工作,最好的方式是在MVC應用程序的登錄操作上調用WebApi認證操作/方法,獲取webapi的認證cookie並在每次調用WebAPI時使用它結束?

任何指導,非常感謝

回答

4

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應用程序。

順便說一下,我剛剛測試了所有這些,所以它的工作原理。

+0

嗨加里,感謝您的答覆。我沒有說我想爲這兩個系統使用同一個cookie,我說我的想法是,當用戶登錄到MVC網站時,在LogOn操作上,我可以以純文本訪問用戶名和密碼,哪一點我想我可以用相同的憑據進行webapi調用以獲得webapi auth cookie,然後使用該cookie用於任何進一步的webapi調用。你有沒有做過? – GR7 2013-05-09 16:14:07

+0

GR7,謝謝澄清。你所說的是正確的。這基本上就是我在迴應的第二部分(以「另一個解決方案......」開頭)所說的。當您的用戶登錄到MVC網站時,您將能夠訪問用戶名和密碼。假設您使用表單身份驗證和爲您生成的默認C#代碼。如果您查看AccountController.cs,您會看到登錄操作。 public ActionResult Login(LoginModel model,string returnUrl){ } – Gary 2013-05-09 20:37:50

+0

在該方法中,您可以使用model.UserName和model.Password訪問用戶名和密碼。然後,您應該能夠調用WebAPI並從中獲取身份驗證Cookie。 – Gary 2013-05-09 20:38:34

相關問題