ASP.NET WebForm 與 MVC 共用 Form 驗證
5 |
我遇到的情境是這樣的:某歷史悠久的網站由新舊程式組成,早期開發是用 WebForm,後期擴充功能時另開了 MVC 專案,所以站台上有兩個 Web Application,一個是 Web Site,一個是 MVC。
架構潔癖者看到這裡可能就怒了,把系統搞成這樣是要怎麼維護? 是不會繼續用 WebForm 寫或乾脆全翻成 MVC 嗎?
唉,繼續用 WebForm 寫新功能會傷心,用 MVC 全部翻新系統會傷肝,還可能危害心血管跟飯碗(想想最近新聞上花一百億砍掉重練的故事...),當痛苦指數仍在可承受範圍內,海納百川是上策呀~
近期接到需求,系統要從 Windows 整合式驗證改為 Form 驗證,憑著第一時間直覺,我捲起袖子自幹了一套簡易版 Single Sign On 身分同步機制,搞到滿頭大汗,但也成功讓 MVC 用 WebForm 的 Form 驗證登入身分。
早上跑步,跑著跑著忽然想到一件事:同一個站台多個 Web Application 的 Cookie 原本就可共享, 而 Form 驗證靠的是 .ASPXAUTH Cookie 配合 Machine Key 加密。因此只要確保 WebForm 與 MVC 的 Form 驗證 Cookie 能互通,就可以做到 Web Form 登入寫入 .ASPXAUTH Cookie, 連上 MVC 時,MVC 解密 .ASPXAUTH Cookie 取出登入身分,即可實現 Web Form 與 MVC 共用登入,根本不需要自己搞 SSO。
跑完步迫不及查資料外加寫程式測試,嘿嘿嘿,還真的讓我做出來了!
先整理一些背景知識:
測試環境如下,IIS 站台有兩個網站專案,FormAuthWebForm 及 FormAuthMvc 分別為 Web Site Project 及 ASP.NET MVC。我將登入頁面放在 WebForm Login.aspx:
Login.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<h3>WebForm</h3>
<form id="form1" runat="server">
<div>
Account:
<asp:TextBox runat="server" id="txtUserId" text="Jeffrey"></asp:TextBox>
</div>
<div>
Password:
<asp:TextBox runat="server" ID="txtPasswd" TextMode="Password"></asp:TextBox>
</div>
<asp:Button runat="server" id="btnLogin" OnClick="btnLogin_OnClick" text="Login"/>
</form>
</body>
</html>
Login.aspx.cs
using System;
using System.Web.Security;
public partial class Login : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnLogin_OnClick(object sender, EventArgs e)
{
var userId = txtUserId.Text;
var passwd = txtPasswd.Text;
//展示用途,省略密碼驗證,直接登入
FormsAuthentication.RedirectFromLoginPage(userId, false);
}
}
AutoFormWebForm/web.config 要設成 Form 驗證。但有幾個注意事項:
- MVC 的 httpRuntime 使用 4.5.2,實測 WebForm 也要配合設成
<httpRuntime targetFramework="4.5.2" />
才會通。 參考 - MVC 與 WebForm 必須使用相同 Machine Key,.ASPXAUTH Cookie 才能同時被兩邊解密驗證,故 Machine Key 不能自動產生,要在 web.config 加上
<machineKey ...>
指定。IIS 管理員有產生 Machine Key 的工具。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<compilation debug="false" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" />
<authentication mode="Forms">
<forms loginUrl="Login.aspx" />
</authentication>
<machineKey decryption="AES" decryptionKey="D1DD...省略..." validation="SHA1" validationKey="4134...省略..." />
<authorization>
<deny users="?" />
</authorization>
<pages controlRenderingCompatibilityVersion="4.0" />
</system.web>
</configuration>
MVC 端也要修改 web.config。首先 machineKey 要跟 WebForm 網站一致,forms loginUrl 指向 /FormAuthWebForm/Login.aspx,defaultUrl 則指向自己的 Home/Index。
<system.web>
<compilation debug="true" targetFramework="4.5.2"/>
<httpRuntime targetFramework="4.5.2"/>
<authentication mode="Forms">
<forms loginUrl="/FormAuthWebForm/Login.aspx" defaultUrl="~/Home/Index"></forms>
</authentication>
<<machineKey decryption="AES" decryptionKey="D1DD...省略..." validation="SHA1" validationKey="4134...省略..." />
<authorization>
<deny users="?"/>
</authorization>
</system.web>
在 Index.cshtml 加入一段程式驗證 MVC 端是否能抓到 WebForm 登入使用者名稱:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
<h3>MVC</h3>
Login User = @User.Identity.Name
</div>
</body>
</html>
實測結果:
掌握這個原則,意味著只要我們能確保 Cookie 可被讀取外加 Machine Key 一致,就能在多個 ASP.NET Web Application 間(不管是 MVC 還是 WebForm,即使在不同站台也可能,只要 Cookie 能互通)共享 Form 驗證登入身分。酷~
【資安提醒】採自行指定 Machine Key 時,decryptionKey 與 validationKey 需視為最高機密嚴密防護,一旦洩漏,惡意人士將可跳過 ASP.NET Form 驗證冒充任何登入帳號。延伸閱讀:MachineKey 外流有多可怕? 淺談 ASP.NET Form 驗證之破解與防護
Tutorial of how to setup to make ASP.NET WebFrom web site and MVC.
Comments
# by pico.chang
設定和圖片的validationKey不一致?
# by Jeffrey
to pico.chang,擷圖與web.config設定是測完模擬場景補拍的,卻不慎穿幫(羞)。已修改,感謝指正。
# by sam
黑大 您好: 我參考網路資料,採用 Windows 整合式驗證: 1. web.config 加 <authentication mode="Windows" /> 2. IIS 10 Windows Authentication 啟用 3. IIS 10 anonymous authentication 停用 可正常執行. 但如果 web.config 不設 <authentication mode="Windows" />, 也可正常執行. 向您請教這兩者的差異. 謝謝您.
# by sam
黑大 您好: 補充說明 我是用 VS 2017 寫測試用的 ASP.NET MVC 程式. 謝謝您.
# by Jeffrey
to sam, 好問題,請參考我的整理 https://blog.darkthread.net/blog/aspnet-and-iis-auth-setting/