分布式中使用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来生成的。感兴趣的可以研究一下这个开源项目:

https://github.com/Azure/aspnet-redis-providers

posted @ 2017-03-30 19:17  wolfy  阅读(1070)  评论(0编辑  收藏  举报