GVKun编程网logo

asp.net-mvc – 为什么Asp.net MVC4不能使用SQL Server会话状态存储的cookieless

14

在这篇文章中,我们将为您详细介绍asp.net-mvc–为什么Asp.netMVC4不能使用SQLServer会话状态存储的cookieless的内容。此外,我们还会涉及一些关于ASP.NETMVC4

在这篇文章中,我们将为您详细介绍asp.net-mvc – 为什么Asp.net MVC4不能使用SQL Server会话状态存储的cookieless的内容。此外,我们还会涉及一些关于ASP.NET MVC4会话状态存储用户名、asp.net mvc4开启SqlServer 会话共享模式、asp.net-core-mvc – 如何在Asp.net Core MVC(又名Asp.Net 5 RC1)中检查响应cookie?、asp.net-mvc – .NET MVC4 Facebook,Google和Twitter登录的知识,以帮助您更全面地了解这个主题。

本文目录一览:

asp.net-mvc – 为什么Asp.net MVC4不能使用SQL Server会话状态存储的cookieless

asp.net-mvc – 为什么Asp.net MVC4不能使用SQL Server会话状态存储的cookieless

ALL,这是我在 Asp.net MVC4应用程序中的Web配置.我发现如果我设置cookieless,一切都很顺利.但如果我不想使用cookie.然后应用程序无法工作.当我调试应用程序时,我发现控制器无法从视图接收任何请求.我认为这是因为在无cookie模式下,Something会被添加到url之前.比如http:// localhost:8119 /(S(3cicpjpagvpunr5he5fnfrj1))/.

<configuration>
  <configSections>
    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup,System.Web.WebPages.Razor,Version=2.0.0.0,Culture=neutral,PublicKeyToken=31BF3856AD364E35">
      <section name="webAssets" type="Telerik.Web.Mvc.Configuration.WebAssetConfigurationSection,Telerik.Web.Mvc" requirePermission="false" />
      <!-- For more information on Entity Framework configuration,visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
      <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection,EntityFramework,Version=4.4.0.0,PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
  </configSections>

  <connectionStrings>
    <add name="..." connectionString="..." providerName="System.Data.sqlClient" />
  </connectionStrings>
  <appSettings>
    <add key="webpages:Version" value="2.0.0.0" />
    <add key="webpages:Enabled" value="true" />
    <add key="PreserveLoginUrl" value="true" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  </appSettings>
  <system.web>
    <customErrors mode="Off" />
    <httpRuntime executionTimeout="14400" maxRequestLength="716800" />
    <compilation debug="true" targetFramework="4.0" />
    <authentication mode="Forms">
      <forms loginUrl="~/Account/Login" timeout="2880" />
    </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.Routing" />
        <add namespace="System.Web.WebPages" />
        <add namespace="Telerik.Web.Mvc.UI" />
      </namespaces>
    </pages>
    <profile defaultProvider="DefaultProfileProvider">
      <providers>
        <add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider,System.Web.Providers,Version=1.0.0.0,PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
      </providers>
    </profile>
    <membership defaultProvider="DefaultMembershipProvider">
      <providers>
        <add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider,PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minrequiredPasswordLength="6" minrequiredNonalphanumericCharacters="0" passwordAttemptwindow="10" applicationName="/" />
      </providers>
    </membership>
    <roleManager defaultProvider="DefaultRoleProvider">
      <providers>
        <add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider,PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
      </providers>
    </roleManager>
    <!-- <sessionState mode="InProc" timeout="30" customProvider="DefaultSessionProvider">
      <providers>
        <add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider,PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
      </providers>
    </sessionState> -->
    <sessionState mode="sqlServer" cookieless="true" sqlConnectionString="data source=xxxx; User ID=xxxx; password=xxxx" timeout="300" sqlCommandTimeout="10" />
    <httpHandlers>
      <add verb="GET,HEAD" path="asset.axd" validate="false" type="Telerik.Web.Mvc.WebAssetHttpHandler,Telerik.Web.Mvc" />
    </httpHandlers>
  </system.web>
  <system.webServer>
    <security>
      <requestfiltering>
        <requestLimits maxAllowedContentLength="3000000000" />
      </requestfiltering>
    </security>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true" />
    <directorybrowse enabled="true" />
    <handlers>
      <remove name="asset" />
      <add name="asset" preCondition="integratedMode" verb="GET,HEAD" path="asset.axd" type="Telerik.Web.Mvc.WebAssetHttpHandler,Telerik.Web.Mvc" />
    </handlers>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.WindowsAzure.StorageClient" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.7.0.0" newVersion="1.7.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
 </configuration>

解决方法

与cookieless =“true”一起使用时,Html.BeginForm()助手(不带任何参数的助手)中存在错误.它在生成URL时不考虑会话ID.所以代替:

<form action="/(S(kkt0zgbnuaoxad23ew33iod4))/home/index" method="post">

它产生:

<form action="/home/index" method="post">

当您发布到/ home / index时,ASP.NET会自动对/(S(kkt0zgbnuaoxad23ew33iod4))进行重定向.重定向意味着GET请求=>你的POST动作永远不会被击中.

作为一种解决方法,您可以编写自定义的Html.BeginForm帮助程序来修复该错误:

public static class FormExtensions
{
    public static Idisposable MyBeginForm(this HtmlHelper htmlHelper)
    {
        var rawUrl = htmlHelper.ViewContext.HttpContext.Request.RawUrl;
        var formAction = htmlHelper.ViewContext.HttpContext.Response.ApplyAppPathModifier("~/") + rawUrl;
        var builder = new TagBuilder("form");
        builder.MergeAttributes(new RouteValueDictionary());
        builder.MergeAttribute("action",formAction);
        builder.MergeAttribute("method",HtmlHelper.GetFormMethodString(FormMethod.Post),true);
        htmlHelper.ViewContext.Writer.Write(builder.ToString(TagRenderMode.StartTag));
        var form = new MvcForm(htmlHelper.ViewContext);
        return form;
    }
}

然后使用:

@using (Html.MyBeginForm())
{
    ...
}

就BeginForm帮助器的其他重载而言,它们应该正常工作并生成包含会话ID的适当操作.

ASP.NET MVC4会话状态存储用户名

ASP.NET MVC4会话状态存储用户名

我用MVC4创建了我的第一个超级小型webapp.到目前为止,我使用布局的东西来布局webapp并添加了一些视图控制器和一个模型来注册并允许用户登录.

用户登录/注册后,我将其用户名存储在会话中.我从会话中读取此属性以确定用户是否已登录.

这是一种不好的做法吗?我读了很多关于RESTful和无状态webapps的内容.我觉得我不应该在会话中保存任何东西.

例如

@if (string.IsNullOrEmpty(Session["User"] as string))
{
    <dl>
        <dt><a href="/Account/Register">Register</a></dt>
        <dt><a href="/Account/Login">Login</a></dt>
    </dl>
}
else
{
    <dl>
        <dt><a href="/Account/ShowAccount/@Session["User"]">@Session["User"]</a></dt>
        <dt><a href="/Account/logout">Log out</a></dt>
    </dl>    
}

Q1:这是一个不好的做法吗?

Q2:这是“黑客安全”吗?这样,是否容易破解当前会话并在Session [“User”]中存储值以绕过登录?

解决方法

回答你的问题:

1)一般来说,使用会话状态并不是一种不好的做法,只要您需要它用于您的应用程序并且您了解它对性能和可伸缩性的影响.但是,在您的情况下,如果您需要存储的只是用户的名称,那么您真的不需要它,如果您的应用程序使用的是ASP.Net成员资格提供程序,那么此信息可在MVCController的User属性中找到基类:

var username = User.Identity.Name

可以存储会话数据的三种方式:“InProc”,它存储在应用程序进程中,“StateServer”,它存储在单独服务器上的输出进程,以及“sqlServer”,它存储在一个单独的服务器上sql Server数据库.您应该使用哪一个取决于您是否正在使用服务器场,如果您的会话需要持久(即在机器重启后仍然存在),以及您的应用程序的性能要求是什么(StateServer和sqlServer的性能不如InProc).更多信息可以在here找到

2)您应该使用SSL来保护会话数据.通过SSL(HTTPS)发送的数据是完全加密的,包括标头(因此是cookie).关于如何防止会话劫持攻击的一个很好的讨论是found here.

asp.net mvc4开启SqlServer 会话共享模式

asp.net mvc4开启SqlServer 会话共享模式

应用部署结构(精简): 输入图片说明

站点部署在Nginx后面,以Nginx作为反向代理,不希望在Nginx上设置ip_hash,实现比较真实的负载均衡效果。

这时考虑到需要让site1site2同时共享会话信息,进行如下的配置:

默认情况下asp.net站点的会话模式是采用Inproc模式,这种模式在站点因IIS重启会导致丢失用户会话(已经登陆的用户会自动重定向到登陆页面),在本次实践中使用SqlServer模式

创建会话数据库(独立于应用):

aspnet_regsql.exe -S server_ip -E -ssadd -sstype c -d dbname

更多参数可以参考命令的帮助aspnet_regsql.exe /?,通常路径在**C:\Windows\Microsoft.NET\Framework64\{.net_version}**下

配置如下:

<sessionState mode="SQLServer" sqlConnectionString="server=server_ip;database=dbname;uid=user;pwd=pwd;" allowCustomSqlDatabase="True" cookieless="false" timeout="20" />

会话数据库的表ASPStateTempApplications中存放应用的信息(appId和AppName),每一个站点一条记录,我两个站点分别使用该数据库所以有两条记录,如图: 输入图片说明

通过以上的配置, 貌似完成了会话的共享,这时候通过NginxIP地址发送两个请求到服务器(一个登陆,一个获取用户考试列表)。通过Nginx的日志发现两次请求被分发到两台不同的后端服务器:

输入图片说明

从图中可以看出第一次请求是192.168.2.2:80803这个站点处理,第二个请求被192.168.2.5:8083这个站点处理。明明已经设置了会话共享为什么第二次请求被提示为未登录。检查是否登陆的代码如下:

 public class WebApiCheckLoginFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            LoginService service = new LoginService();
            string controllerName = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            string actionName = actionContext.ActionDescriptor.ActionName;
            bool isAuthAction = controllerName.Equals("ExamAPI") && actionName.Equals("Login");
            if (!isAuthAction)
            {
                HttpSessionState Session = System.Web.HttpContext.Current.Session;
                if (Session["user"] == null)
                {
                    throw new HttpException((int)HttpStatusCode.NonAuthoritativeInformation, "未登录用户或已在其他设备中登录");
                }
                if (!service.IsOnline(Model.DeviceType.Phone, Session.SessionID))
                {
                    throw new HttpException((int)HttpStatusCode.NonAuthoritativeInformation, "未登录用户或已在其他设备中登录");
                }
            }
            base.OnActionExecuting(actionContext);
        }
    }

上述代码是为了检查如果session[''user'']==null,就会提示是未登陆。已经配置了会话共享为什么session[''user'']还是获取不到用户对象?通过各种尝试发现asp.net在处理session的时候会根据站点的AppId加上浏览器上的SessionId在数据库表([ASPStateTempSessions])中创建会话记录,SessionId的值如下:

0kf0zoq4to3h0z0b1eztw43s28d8c075
  • 28d8c075 是AppId685293685的16进制(对应的AppId)
  • 0kf0zoq4to3h0z0b1eztw43s是客户端cookie中存放的sessionid

通过查看存储过程[dbo].[TempGetAppID]的代码,发现asp.net会通过每个站点的AppName(见表ASPStateTempApplications)去获取AppId,然后将SessionId+AppId(16进制)作为主键插入到表ASPStateTempSessions中,这样的处理逻辑是保证一个会话数据库会被N个站点共同使用,不用每个站点创建自己的会话数据库。隐藏的问题是如果站点的AppName不一样会导致获取的AppId不一样达不到会话共享的目的。

验证过程如下:向Nginx发送两个请求(一个登陆,一个获取考试列表)会在ASPStateTempSessions表中产生两条记录,正常情况应该两个请求也应该只产生一条会话记录。

为了保证只产生一条会话记录可以通过让site1site2的AppName保持一致,每次通过存储过程 [dbo].[TempGetAppID]获取的AppId都是同一个。 修改方式为: 输入图片说明

修改完成后,再次发送两个请求(一个登陆,一个获取考试列表),两个请求经过Nginx分发到两个站点后在ASPStateTempSessions只产生一条会话记录,这样才真正的实现会话的一致性。

配置machineKey,在做asp.net站点集群的时候如果站点中使用到cookieviewstate的话需要配置machineKey来确保多台机器共享验证和ViewState.每个节点上的machineKey配置必须一致

按照MSDN的标准说法:“对密钥进行配置,以便将其用于对 Forms 身份验证 Cookie 数据和视图状态数据进行加密和解密,并将其用于对进程外会话状态标识进行验证.加密和解密使用的就是machineKey

生成machineKey的代码

public static string CreateMachineKey(int length)
        {
            byte[] random = new byte[length / 2];
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            rng.GetBytes(random);
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < random.Length; i++)
            {
                builder.Append(string.Format("{0:X2}", random[i]));
            }
            return builder.ToString();

        }
   string decryptionKey= CreateMachineKey(48);
   string validationKey = CreateMachineKey(128);

web.config配置内容

<system.web>
     
    <compilation targetFramework="4.0" />
    <machineKey validationKey="validationKey" decryptionKey="decryptionKey"/>
...other...
     </system.web>

小结

asp.net 站点的会话模式如果选用SqlServer的话,需要保证站点群(可能有N个站点)通过[dbo].[TempGetAppID]存储过程获取AppId后的结果是相同的。可以通过修改存储过程,也可以通过修改AppName。

asp.net-core-mvc – 如何在Asp.net Core MVC(又名Asp.Net 5 RC1)中检查响应cookie?

asp.net-core-mvc – 如何在Asp.net Core MVC(又名Asp.Net 5 RC1)中检查响应cookie?

我正在将一个Web表单应用程序转换为asp.net core mvc.在我的Web表单应用程序中,有时在我设置一些响应cookie后,其他代码需要查看它们是否已设置,如果是,请访问cookie的属性(即value,Expires,Secure,http).在webforms和MVC 5中,可以迭代cookie并返回任何特定的cookie,如此(我知道的老学校)
for(int i = 0; i < cookies.Count; i++) {
            if(cookies[i].Name == cookieName) {
                return cookies[i];
            }
        }

但是在asp.net core mvc中访问响应cookie的界面如下所示:

基于此接口,我没有看到检查响应cookie是否存在并获取其属性的方法.但是还有一些方法可以做到吗?

在一个动作方法中,我尝试在响应对象上设置两个cookie,然后立即尝试访问它们.但intellisense没有显示允许我访问它们的任何方法,属性或索引器:

有一会儿,我想也许我可以使用Response.Cookies.ToString();并且只是解析信息以找到我的cookie信息,但是,ToString()调用返回“Microsoft.AspNet.Http.Internal.ResponseCookies”,因为该对象不会覆盖默认实现.

只是为了好玩,我还检查了GitHub的当前dev分支,看看自RC1以来接口是否已经改变,但它没有.所以给定这个接口,我如何检查响应cookie的存在并获取它的属性?我曾经考虑过通过响应头集合进行攻击,但这看起来很蹩脚.

解决方法

这是我如何从Response中获取cookie的值.如果需要,这样的东西可用于获取整个cookie:
string GetCookieValueFromresponse(HttpResponse response,string cookieName)
{
  foreach (var headers in response.Headers.Values)
    foreach (var header in headers)
      if (header.StartsWith($"{cookieName}="))
      {
        var p1 = header.IndexOf('=');
        var p2 = header.IndexOf(';');
        return header.Substring(p1 + 1,p2 - p1 - 1);
      }
  return null;
}

asp.net-mvc – .NET MVC4 Facebook,Google和Twitter登录

asp.net-mvc – .NET MVC4 Facebook,Google和Twitter登录

我正在使用.NET MVC4,我想要一个auth扩展Facebook,Google&推特.
我下载了DotNetopenAuth 4.1,但我在网上找不到任何关于如何将它与我的应用程序集成的示例,并在我的视图中有一个提供程序的登录表单.

谢谢

解决方法

你不需要做任何事情. MVC4在默认的Internet模板中包含此功能.

只需生成一个新的MVC4应用程序,选择互联网模板,运行它并使用您的Facebook ID登录.

我们今天的关于asp.net-mvc – 为什么Asp.net MVC4不能使用SQL Server会话状态存储的cookieless的分享已经告一段落,感谢您的关注,如果您想了解更多关于ASP.NET MVC4会话状态存储用户名、asp.net mvc4开启SqlServer 会话共享模式、asp.net-core-mvc – 如何在Asp.net Core MVC(又名Asp.Net 5 RC1)中检查响应cookie?、asp.net-mvc – .NET MVC4 Facebook,Google和Twitter登录的相关信息,请在本站查询。

本文标签: