[英]HttpContext.User NullReferenceException only on deployed server
我在我的 MVC 項目上使用 formsauthentication,當使用 Visual Studio Development Server 在本地進行測試時,一切都按預期工作。 一旦部署到 IIS 7.5, HTTPContext.User
就會導致NullReferenceException
s。
Dev 和 Prod 機器都使用相同的 SQL 數據庫(目前 - 這當然會在部署后改變)所以我知道這不是數據庫或其中的數據的問題。
這必須是 IIS 或我的 web.config 中的設置,但我找不到它。 我已經嘗試對我的 web.config 進行各種更改(根據我在 SE 周圍找到的建議),這是我的 web.config 的一部分,用於當前實現:
<appSettings>
<add key="autoFormsAuthentication" value="true" />
<add key="enableSimpleMembership" value="false" />
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="PreserveLoginUrl" value="true" />
<add key="ClientValidationEnabled" value="true" />
****Snip****
<system.web>
<httpRuntime targetFramework="4.5" />
<compilation debug="true" targetFramework="4.5" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" cookieless="UseCookies"/>
</authentication>
<pages>
<namespaces>
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Optimization" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
<add namespace="ProjectSquid.WebUI.HTMLHelpers" />
</namespaces>
</pages>
<roleManager enabled="true" defaultProvider="CustomRoleProvider">
<providers>
<clear />
<add name="CustomRoleProvider"
type="Project.Domain.Filters.CustomRoleProvider"
connectionStringName="EFDbContext"
enablePasswordRetrieval="false"
cacheRolesInCookie="true"/>
</providers>
</roleManager>
<membership defaultProvider="SimpleMembershipProvider">
<providers>
<clear />
<add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>
<sessionState mode="InProc" customProvider="DefaultSessionProvider">
<providers>
<add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="EFDbContext" />
</providers>
</sessionState>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-UA-Compatible" value="IE=9" />
</customHeaders>
</httpProtocol>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<modules runAllManagedModulesForAllRequests="false">
<remove name="FormsAuthentication" />
<remove name="DefaultAuthentication" />
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition="" />
<add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" preCondition="" />
<remove name="UrlRoutingModule-4.0"/>
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" preCondition="" />
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
</modules>
</system.webServer>
是什么導致HttpContext.User
與 VS 開發服務器和 IIS 7.5 實現不同?
編輯:
HttpContext
通過繼承的 BaseController 提供:
protected virtual new CustomPrincipal User
{
get { return HttpContext.User == null? null : HttpContext.User as CustomPrincipal; }
}
public new HttpContextBase HttpContext
{
get
{
return ControllerContext == null ? null : ControllerContext.HttpContext;
}
}
直到 PostAuthenticationRequest 才會創建 cookie:
public void MvcApplication_PostAuthenticationRequest(object sender, EventArgs e)
{
var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
string encTicket = authCookie.Value;
if (!String.IsNullOrEmpty(encTicket))
{
var ticket = FormsAuthentication.Decrypt(encTicket);
var id = new UserIdentity(ticket);
string[] userRole = Roles.GetRolesForUser(id.Name);
var prin = new CustomPrincipal(id);
HttpContext.Current.User = prin;
Thread.CurrentPrincipal = prin;
}
}
}
身份驗證本身似乎工作正常,因為導致異常的 function 以[Authorize]
開頭並成功開始執行,但在到達第一個用戶引用時失敗為null
:
int userT = User.Team.TeamId;
在這種情況下,用戶是CustomPrincipal
BaseController.User
。
編輯2:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880"
cookieless="UseCookies"
name=".ASPXAUTH"
protection="All"
slidingExpiration="true"/>
</authentication>
編輯3
自定義IIdentity
:
[Serializable]
public class UserIdentity : MarshalByRefObject, IIdentity
{
private readonly FormsAuthenticationTicket _ticket;
public UserIdentity(FormsAuthenticationTicket ticket)
{
_ticket = ticket;
}
public string AuthenticationType
{
get { return "Custom"; }
}
public bool IsAuthenticated
{
get { return !string.IsNullOrEmpty(this.Name); }
}
public string Name
{
get { return _ticket.Name; }
}
public string UserId
{
get { return _ticket.UserData; }
}
public bool IsInRole(string Role)
{
return Roles.IsUserInRole(Role);
}
public IIdentity Identity
{
get { return this; }
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (context.State == StreamingContextStates.CrossAppDomain)
{
GenericIdentity gIdent = new GenericIdentity(this.Name, this.AuthenticationType);
info.SetType(gIdent.GetType());
System.Reflection.MemberInfo[] serializableMembers;
object[] serializableValues;
serializableMembers = FormatterServices.GetSerializableMembers(gIdent.GetType());
serializableValues = FormatterServices.GetObjectData(gIdent, serializableMembers);
for (int i = 0; i < serializableMembers.Length; i++)
{
info.AddValue(serializableMembers[i].Name, serializableValues[i]);
}
}
else
{
throw new InvalidOperationException("Serialization not supported");
}
}
自定義IPrincipal
:
interface ICustomPrincipal : IPrincipal
{
int Id { get; set; }
string Name { get; set; }
string Role { get; set; }
}
public class CustomPrincipal : IPrincipal
{
public CustomPrincipal(UserIdentity identity)
{
this.Identity = identity;
}
public IIdentity Identity { get; private set; }
很可能,您正試圖在HttpContext.User
初始化之前檢索它。 此行為在 IIS 經典(或 Visual Studio Web 服務器)和 IIS 集成管道模式之間有所不同,這可以解釋為什么您在環境之間看到不同的行為。
解釋
HttpContext
是應用程序運行時的一部分 state 。 在現代托管環境(IIS 集成管道模式和 OWIN)中,直到Application_Start
方法完成后才會填充HttpContext
。 您擁有的任何需要HttpContext.User
的行為都不應在Application_BeginRequest
事件或之后執行。
參考: 請求在此上下文中不可用
從您的帖子中不清楚,因為配置身份驗證取決於項目中的各種設置以及配置文件。 例如在Web.config文件中,有幾個地方可以像這樣自定義/配置身份驗證(最重要的規則),但您還沒有放在帖子中:
<system.web>
<authentication mode="" />
</system.web>
如您所知,由於配置系統基於使用 **.config* 文件的管理系統的分層系統,因此您應該考慮默認值,也許通過<remove/>
或<add/>
一些參數。 IIS 7 及更高版本的配置文件位於您的%WinDir%\System32\.netsrv\Config
文件夾中,主要配置文件為:
注意:某些設置可以委托給Web.config文件,這些文件可能會覆蓋ApplicationHost.config文件中的設置。 此外,未委托的設置無法添加到Web.config文件中。
提示:IIS 7 的默認安裝不包含 Digest 身份驗證,因此在安裝 Digest 身份驗證模塊之前,將 Digest 身份驗證的設置添加到ApplicationHost.config將不起作用或可能導致錯誤。
您需要查看本地和部署配置以滿足您的目的。 如果您在使用集成管道時遇到問題,請參閱以下頁面以利用它的優勢:
關於SlidingExpiration
的更新:根據MSDN :
如果發出請求並且超過一半的超時間隔已過去,則滑動過期會重置有效身份驗證 cookie 的過期時間。
如果 cookie 過期,用戶必須重新進行身份驗證。 將SlidingExpiration
屬性設置為false
可以根據配置的超時值限制身份驗證 cookie 的有效時間,從而提高應用程序的安全性。 所以我認為沒有必要將它用作false
。 這意味着如果在該時間段內沒有任何請求,它將在激活緩存時的時間段后使緩存過期。 當有太多數據要緩存時,這種類型的過期很有用。 所以它將那些在應用程序中經常使用的項目放入緩存中。 所以它不會使用不必要的 memory。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.