MVC Sessionid问题

龟叔啊 2018-05-04 10:56:53
本人最近开发一个MVC4项目,项目的使用角色有学生和老师,所以登录页面存在两个登录表单,分别有两个登录验证码
登录界面如图:




两种角色登录验证码使用session分别保存。视图逻辑代码如下:
两个<img>指向一个获取验证码图片的流地址:

<img src="/Admin/Account/NumberValidateImg?userType=teacher" id="teachervalidimg" class="login-code" onclick="ShowValidate('teacher')" />
<img src="/Admin/Account/NumberValidateImg?userType=student" id="studentvalidimg" class="login-code" onclick="ShowValidate('student')" />


服务端生成验证码代码:

//控制器生成登录验证码
public FileContentResult NumberValidateImg(string userType)
{
ValidateCode validateCode = new ValidateCode();
var ms = validateCode.CreateNumberCode(userType, 4);
Response.BinaryWrite(ms.ToArray());
return File(ms.ToArray(), MediaTypeNames.Image.Jpeg);
}




validateCode类中的生成方法,注意这里我用session保存了验证码,以便后续进行登录验证


/// <summary>
/// 创建数字验证码
/// </summary>
/// <param name="textLength">数字的长度</param>
/// <returns>返回图片内存流</returns>
public MemoryStream CreateNumberCode(string strUserType,int textLength)
{
int ranCount = textLength;
string outcode = "";
Random ran = new Random();
for (int h = 0; h < ranCount; h++)
{
outcode += ran.Next(9).ToString();
}
MemoryStream m = CreateTextImage(outcode);
HttpContext.Current.Session[strUserType+"ValidateImgCode"] = outcode;
return m;
}

具体生成验证码的内容这里我就不贴了。

不同用户点击登录时异步提交到同一个控制器的不同action中验证,以下是教师登录验证代码:

[AnonymousAttribute]
[HttpPost]
public JsonResult TeacherLogin([Bind(Prefix = "Teacher")] TeacherLoginModel model)
{
try
{
model.IsRemind = false;
//验证码开启状态
if (!new ValidateCode().IsUseValidate)
ModelState.Remove("Teacher.ValidateCode");
if (!ModelState.IsValid)
{
foreach (var state in ModelState)
{
foreach (var err in state.Value.Errors)
{
return Json(new
{
Code = "-1",
Desc = err.ErrorMessage
});
}
}
}
//登录
AdminSystemLogin adminSystemLogin = new AdminSystemLogin(model.UserName, model.Password, model.ValidateCode, model.IsRemind);
var response = adminSystemLogin.Login();
return Json(response);
}
catch (Exception ex)
{
return Json(new
{
Code = "-1",
Desc = ex.Message
});
}
}


adminSystemLogin.Login()里是具体登录验证,代码如下:

public ResponseModel Login()
{
ResponseModel response = new ResponseModel();
response.Code = "0";
response.Desc = "效验成功";
//验证码效验
if (_validateCode.IsUseValidate) {
if (!_validateCode.ValidateImgCode("teacher",this.validateCode)) {
response.Code = "-1";
response.Desc = "验证码错误";
return response;
}
}
.....................................
return response;
}

_validateCode.ValidateImgCode()方法验证代码如下:

/// <summary>
/// 验证码效验
/// </summary>
/// <param name="validateCode">用户输入的验证码</param>
/// <returns></returns>
public bool ValidateImgCode(string strUserType,string validateCode)
{
bool result = true;
if (HttpContext.Current.Session[strUserType+"ValidateImgCode"] == null || !string.Equals(HttpContext.Current.Session[strUserType+"ValidateImgCode"].ToString(), validateCode, StringComparison.OrdinalIgnoreCase))
{
result = false;
}
return result;
}


现在开始描述问题,使用时发现用户第一次访问网站(无cookie记录)第一次点击教师角色登录时验证码永远提示错误,再次更改验证码点击登录成功,通过服务端代码跟踪发现教师和学生保存的验证码sessionid竟然不同,而浏览器cookie显示的sessionid是学生验证码保存的sessionid,再次通过浏览器调试发现教师验证码请求时request headers头部没有包含set-cookie的sessionid信息而第二个请求学生验证码的图片确有附带sessionid信息,调试代码截图如下:










从上面的截图可以看出两次请求sessionid不同,且浏览器cookie最终保存的sessionid是学生验证码的那个请求返回的sessionid,这造成了教师登录验证时取对应session的值是空的:



当然网上的解决方案可以搜到,就是在Global.asax文件中加入session_start和session_end事件:


protected void Session_Start(object sender, EventArgs e)
{
//加入这个方法是为了解决第一次请求sessionid变化问题,具体原因未知
}

protected void Session_End(object sender, EventArgs e)
{
//加入这个方法是为了解决第一次请求sessionid变化问题,具体原因未知
}


我想问的问题是:1:为什么sessionid会变化?2.为什么使用了那两个事件就可以了。这其中的原理是什么,请大神赐教!

...全文
852 16 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
(即使是)不同的ie(或者其它浏览器)窗口进程也是使用同一套cookie,这个你不会不知道吧? 你怎么做到两个身份的人在你的电脑桌面同时登录?
  • 打赏
  • 举报
回复
在 html5 发布了这么多年的时代背景下,其实使用 h5 客户端存储机制,而不应该使用 cookie 了。我不知道别的公司对前端有没有这个基本要求,我们是从来关心 cookie。
引用 9 楼 heather_suyisi 的回复:
谢谢回答,应该是你讲的符合逻辑,另外你说的应该在返回登陆页时就开启session,所谓开启是指在登陆显示action中设置一个session (即使存一个空值)是吗?还有我发现如果没有登陆验证码浏览器cookie就没有存储sessionid是不是说如果服务端没有使用session那么就不会创建sessionid?
如果没往Session集合里边写东西,那么asp.net 的SessionID 就是随机变化的,还不能使用。只有服务器端先往Session集合里边保存东西,才能期望以后正常使用Session(其实这个逻辑很自然),此时SessionID才稳定不变。这个是 asp.net 的经常考试的知识。
xuzuning 2018-05-05
  • 打赏
  • 举报
回复
我不知道你的 MVC 是如何启用 Session 的 是否是向 HttpContext.Current.Session 赋值就算启用了? 如果是,那你就在生成登录页面的代码里赋值一个,比如时间 总之应在登录画面出现时就出现 Set-Cookie: ASP.NET_SessionId=...............
  • 打赏
  • 举报
回复
那两个问题是次要的。你说你分别使用两个登录页面,别说是两个页面,就算是同时i可打开两个浏览器进程,其 SessionID 也是相同的,那么也是最多只能支持一个人登录!!!!
  • 打赏
  • 举报
回复
如果你说的是“SessionID为空”的情况,那么对于 asp.net 来说,要先在服务器往Session集合写内容,然后才能使用。你确保两个测试,每一个页面在下载时都事先向服务器端 Session 集合写了内容了吗?分别贴出调试信息来看看。 我其实已经说了,不要使用 Sesson 集合,这样就能避开有关Session的许多问题(例如Session 内容容易丢失的问题)。缓存数据写到Cache 中就可以了,而使用 SessonID就可以用来访问 Cache 的各种用户身份数据,修改数据时应该实时写入数据库、并且用Cache作为缓存,完全用不着经常自动就丢失数据的 Session 集合。
龟叔啊 2018-05-05
  • 打赏
  • 举报
回复
引用 12 楼 sp1234 的回复:
在 html5 发布了这么多年的时代背景下,其实使用 h5 客户端存储机制,而不应该使用 cookie 了。我不知道别的公司对前端有没有这个基本要求,我们是从来关心 cookie。 [quote=引用 9 楼 heather_suyisi 的回复:] 谢谢回答,应该是你讲的符合逻辑,另外你说的应该在返回登陆页时就开启session,所谓开启是指在登陆显示action中设置一个session (即使存一个空值)是吗?还有我发现如果没有登陆验证码浏览器cookie就没有存储sessionid是不是说如果服务端没有使用session那么就不会创建sessionid?
如果没往Session集合里边写东西,那么asp.net 的SessionID 就是随机变化的,还不能使用。只有服务器端先往Session集合里边保存东西,才能期望以后正常使用Session(其实这个逻辑很自然),此时SessionID才稳定不变。这个是 asp.net 的经常考试的知识。[/quote] 问题是我们开发的某些网站还不全在html5下运行。尤其是IE浏览器简直是个灾难。
龟叔啊 2018-05-05
  • 打赏
  • 举报
回复
引用 11 楼 sp1234 的回复:
(即使是)不同的ie(或者其它浏览器)窗口进程也是使用同一套cookie,这个你不会不知道吧? 你怎么做到两个身份的人在你的电脑桌面同时登录?
谢谢回答,我没有要实现两个身份同时在一台登录,只是给他个选择而已。另外你说的没有往Session存东西sessionid就会随机变化,我的理解是如果没有使用session存东西,服务端不会产生sessionid并返回给客户端,我测试看到的结果也是这样的,除非你在Global.asax文件中加入session_start和session_end事件这是即使你没有使用session服务端也会创建sessionid给客户端,不知道我测试或者理解有误?
龟叔啊 2018-05-05
  • 打赏
  • 举报
回复
引用 6 楼 xuzuning的回复:
原因是你的登录页面没有 sessionid,验证时所需的 sessionid 是由 验证码图片连接产生的 连接或ajax 会携带 cookie,但你的两个验证码图片连接都因没有初始的cookie可携带,从而会有两个 sessionid 被返回 <img src="/Admin/Account/NumberValidateImg?userType=teacher" id="teachervalidimg" class="login-code" onclick="ShowValidate('teacher')" /> <img src="/Admin/Account/NumberValidateImg?userType=student" id="studentvalidimg" class="login-code" onclick="ShowValidate('student')" /> 对浏览器而言是同时发出请求的的,但不能知道谁会先返回
谢谢回答,应该是你讲的符合逻辑,另外你说的应该在返回登陆页时就开启session,所谓开启是指在登陆显示action中设置一个session (即使存一个空值)是吗?还有我发现如果没有登陆验证码浏览器cookie就没有存储sessionid是不是说如果服务端没有使用session那么就不会创建sessionid?
龟叔啊 2018-05-05
  • 打赏
  • 举报
回复
引用 5 楼 正怒月神的回复:
“不同用户点击登录时异步提交到同一个控制器的不同action中验证” 既然你使用了异步。那么就和sessionid没有关系了。 因为异步默认是不会携带 cookie的,所以更加不会有sessionid了。
谢谢回答,如果根据你的思路来讲,为啥根据网上的设置后,同样异步登陆就可以了取到session 值了?异步是否携带session id我明天可以验证下。
正怒月神 2018-05-04
  • 打赏
  • 举报
回复
“不同用户点击登录时异步提交到同一个控制器的不同action中验证” 既然你使用了异步。那么就和sessionid没有关系了。 因为异步默认是不会携带 cookie的,所以更加不会有sessionid了。
  • 打赏
  • 举报
回复
引用 2 楼 heather_suyisi 的回复:
[quote=引用 1 楼 xomix 的回复:] 1:为什么sessionid会变化? 因为在默认状态下,一个浏览器请求和这个浏览器请求内的ajax是不同的请求,会获取到不同的session id。
图片的请求应该不属于ajax请求吧?[/quote] 这个就没有具体试过了,mvc5之后我没有再用过session,因为这东西对于mvc5来说属于过时的。
龟叔啊 2018-05-04
  • 打赏
  • 举报
回复
引用 1 楼 xomix 的回复:
1:为什么sessionid会变化? 因为在默认状态下,一个浏览器请求和这个浏览器请求内的ajax是不同的请求,会获取到不同的session id。
再说ajax请求也会附带sessionid吧?
龟叔啊 2018-05-04
  • 打赏
  • 举报
回复
引用 1 楼 xomix 的回复:
1:为什么sessionid会变化? 因为在默认状态下,一个浏览器请求和这个浏览器请求内的ajax是不同的请求,会获取到不同的session id。
图片的请求应该不属于ajax请求吧?
  • 打赏
  • 举报
回复
1:为什么sessionid会变化? 因为在默认状态下,一个浏览器请求和这个浏览器请求内的ajax是不同的请求,会获取到不同的session id。 2.为什么使用了那两个事件就可以了。 这两个事件我第一次见到,因为以前解决这个都是用token的,我查了很久没找到这两个事件的作用,我认为这两个事件应该是将浏览器内的所有请求视为一个请求的一种服务端配置方法吧。
xuzuning 2018-05-04
  • 打赏
  • 举报
回复
你只要在产生登录表单页面时就开启 Session 就可以了 那两个 验证码图片连接 都会携带这个预置的 sessionid 当然 Session 中的两个验证码值是需要分别保存的
xuzuning 2018-05-04
  • 打赏
  • 举报
回复
原因是你的登录页面没有 sessionid,验证时所需的 sessionid 是由 验证码图片连接产生的 连接或ajax 会携带 cookie,但你的两个验证码图片连接都因没有初始的cookie可携带,从而会有两个 sessionid 被返回 <img src="/Admin/Account/NumberValidateImg?userType=teacher" id="teachervalidimg" class="login-code" onclick="ShowValidate('teacher')" /> <img src="/Admin/Account/NumberValidateImg?userType=student" id="studentvalidimg" class="login-code" onclick="ShowValidate('student')" /> 对浏览器而言是同时发出请求的的,但不能知道谁会先返回

111,098

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧