分布式中使用redis进行session共享
摘要
在asp.net web中,session经常用来存储当前用户信息,或者通过session进行登录权限的验证。如果是一台服务器,session的使用没问题,如果使用nginx等实现反向代理,将站点部署在多台服务器的情况下,有可能出现这样的现象:你登录的时候是在服务器A登录,并且采用的session存储是进程内存储的方式,你在访问其他页面的情况下,nginx有可能将你的请求转发到服务器B,但服务器B进程内并没有保存你的用户信息,在校验权限的时候,会将你重定向到登录页面。
解决方案
首先需要了解asp.net的session几种存储方式,可以在web.config中进行设置。如图所示:
InProc
服务器的Session存储在IIS进程中,当IIS关闭,重启时,这些Session信息就会丢失,但这种模式最大的好处就是性能提高。但也有缺点,伴随着iis重启或应用重启,session将会丢失。
StateServer
此种方式独立于IIS进程,使用此种方式需要在服务器上开启ASP.NET State Service服务。
Off
表示不使用Session功能。
SQLServer
表示将Session存储在SQL Server。
Custom
自定义存储。
在使用Redis存储的时候可以使用nuget中的一个组件。如图所示:
安装成功之后,需要在web.config中生成配置项,根据实际项目进行配置。如图所示:
设置host(redis服务器ip),databaseId(数据库索引),accessKey(账户pwd)信息。
一个例子
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using Wolfy.RedisSession.Models; namespace Wolfy.RedisSession.Controllers { public class HomeController : Controller { // GET: Home public ActionResult Login() { return View(); } [HttpPost] public JsonResult Login(UserViewModel user) { if (!ModelState.IsValid) { return new JsonResult { Data = new { _code = 400, _msg = "Login err" }, JsonRequestBehavior = JsonRequestBehavior.DenyGet }; } if (user.Name == "wolfy" && user.Pwd == "12345") { Session["user"] = user; return new JsonResult { Data = new { _code = 200, _msg = "Login Success" }, JsonRequestBehavior = JsonRequestBehavior.DenyGet }; } else { return new JsonResult { Data = new { _code = 400, _msg = "Login err" }, JsonRequestBehavior = JsonRequestBehavior.DenyGet }; } } public ActionResult List() { UserViewModel user = Session["user"] as UserViewModel; if (user == null) { return new HttpUnauthorizedResult(); } return View(); } } }
@model Wolfy.RedisSession.Models.UserViewModel @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Login</title> </head> <body> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>UserViewModel</h4> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <div class="form-group"> @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Pwd, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Pwd, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Pwd, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Login" class="btn btn-default" /> </div> </div> </div> } <div> @Html.ActionLink("Back to List", "Index") </div> </body> </html>
上面的代码片段很简单,登录成功后将用户信息保存在session["user"]中,在访问List视图的时候,需要进行是否登录的验证。如果session为空,则返回未授权,否则向用户展示list视图。
如果在没登录直接访问list,如图所示:
登录
刷新list页面,就可以正常访问了。
看一下redis中保存的内容
我们都知道,在没禁用cookie的情况下,session_id是存储在cookie中的,那么我们看一下请求中的sessionid跟redis的key是否有关系?
看来Redis中用来保存session的键是根据Session_id来生成的。感兴趣的可以研究一下这个开源项目:
-
博客地址:http://www.cnblogs.com/wolf-sun/
博客版权:如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步! 再次感谢您耐心的读完本篇文章。