结合cookie和session,把登陆流程梳理的清清楚楚

结合cookie和session,把登陆流程梳理的清清楚楚

本文为小编原创文章,首发于Java识堂,一个高原创,高收藏,有干货的微信公众号,一起成长,一起进步,欢迎关注

前言

原来分享过一篇文章,Java自定义注解及应用,当时为了能突出重点,直接在url中传了用户的所属角色,并写了一般的做法。加上最近看了一些人的简历,发现神奇的相似,都有类似商城的项目,为了不至于问些特别Low的问题,便总结了一下登录这个模块所涉及的东西

单机Session

Http协议使用的是无状态连接,这样会造成什么问题呢?看如下Demo

结合cookie和session,把登陆流程梳理的清清楚楚

结合cookie和session,把登陆流程梳理的清清楚楚

测试

结合cookie和session,把登陆流程梳理的清清楚楚


结合cookie和session,把登陆流程梳理的清清楚楚


HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,当在一个请求中时HttpServletRequest中的信息可以共享,而在不同的请求中HttpServletRequest并不能共享,这样就会造成用户确实进行过登录操作,但是跳到购物车页面时发现并没有东西,因为应用并不知道访问这个页面的用户是谁

我们可以用一个HttpSession对象保存跨多个请求的会话状态,上面的例子就是保存用户名,看下图理解为什么HttpSession可以跨请求保存状态


结合cookie和session,把登陆流程梳理的清清楚楚


结合cookie和session,把登陆流程梳理的清清楚楚


对客户的第一个请求,容器会生成一个唯一的会话ID,并通过响应把它返回给客户。客户再在以后的每一个请求中发回这个会话ID。容器看到ID后,就会找到匹配的会话,并把这个会话与请求关联

将上面代码改成如下,再测试

结合cookie和session,把登陆流程梳理的清清楚楚


结合cookie和session,把登陆流程梳理的清清楚楚


果然能保存会话状态了,客户和容器如何交换会话ID信息呢?其实是通过cookie实现的


结合cookie和session,把登陆流程梳理的清清楚楚

结合cookie和session,把登陆流程梳理的清清楚楚

看上面能保存会话的代码,我们并没有对cookie进行操作啊,其实是容器几乎会做cookie的所有工作,从最开始的Servlet开始讲这些操作是如何实现的,先看一下Servlet执行过程

  1. 用户点击页面发送请求->Web服务器应用(如Apache)->Web容器应用(如tomcat)
  2. 容器创建两个对象HttpServletRequest和HttpServletResponse
  3. 根据URL找到servlet,并为请求创建或分配一个线程,将请求和响应对象传递给这个servlet线程
  4. 容器调用Servlet的service()方法,根据请求的不同类型,service()方法会调用doGet()和doPost()方法,假如请求是HTTP GET请求
  5. doGet()方法生成动态页面,并把这个对象塞到响应对象里。容器有响应对象的一个引用
  6. 线程结束,容器把响应对象装换为一个HTTP请求,把它发回给客户,然后删除请求和响应对象

容器使用部署描述文件把URL映射到Servlet ,一个Servlet可以有3个名字,(1)用户知道的URL名,(2)部署人员知道的内部名,(3)实际的文件名

加入使用Spring MVC时要在web.xml中配置如下内容

结合cookie和session,把登陆流程梳理的清清楚楚

根据url-pattern->servlet-name->servlet-class的三级映射关系,容器即可根据用户输入的URL找到对应的Servlet

从这个就可以看出其实Spring MVC框架其实在Servlet上面封装了一层,当我们自己用Servlet编写程序时,可以从HttpServletRequest中获取HttpSession,如下

public class LoginServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

HttpSession session = req.getSession();
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

super.doPost(req, resp);
}
}

在响应中发送一个会话cookie

HttpSession session = req.getSession();


我们只需要写上述一行代码即可,来看看容器帮我们做了哪些事情

  1. 建立一个新的HttpSession对象
  2. 生成唯一的会话ID
  3. 建立新的Cookie对象
  4. 把会话Id放到cookie中
  5. 在响应中设置cookie

从请求得到会话ID

HttpSession session = req.getSession();


与响应生成会话ID和cookie时用的方法一样

if (请求包含一个会话ID cookie) {
找到与该ID匹配的会话
} else if (没有会话Id cookie OR 没有与此会话ID匹配的当前会话) {
创建一个新会话
}


如上面用的方法,我们并没有直接从HttpServletRequest 中获取HttpSession

public String login(HttpSession session, @RequestParam("username") String username)


能直接获取到HttpSession,其实是框架帮我们执行了HttpSession session = req.getSession(),然后设置进来的。我们可以设置session的过期时间,以保证用户登录后长期不操作需要重新登录

分布式Session

当整个服务是分布式的该怎么处理呢?用户在服务器A上登录,结果在服务器B上查看购物车信息,因为在A上登录,HttpSession存在A服务器上,当访问B服务器上的购物车信息因为获取不到用户登录的HttpSession,就会认为用户没有登录,这种情况该怎么处理呢?

实现分布式Session有多种方式,这里就介绍一下用Redis实现分布式Session,其实Spring Session项目就使用Redis实现Session共享的

理解了单机Session,分布式Session也不难理解,主要步骤如下

  1. 用户登录以后,先生成类似于sessionId的唯一标识,我们把它叫token
  2. new一个cookie,将token写到cookie当中传递到客户端,并将以key=token,value=用户信息的hash放到redis中,当然cookie和这个hash都可以设置过期时间
  3. 客户端在随后的访问中服务器从cookie中拿到这个token,根据这个token去Redis中取到用户信息

当用户登出时只要删除key为token的hash,并且将cookie的最长时间设置为0,重新放回HttpServletResponse即可,鉴于篇幅限制,就不写具体代码了

为什么要在密码中加盐

直接存储

以前系统存储密码时都是类似如下形式

结合cookie和session,把登陆流程梳理的清清楚楚

假如用户信息泄露,用户的账号安全将受到威胁,参考CSDN密码泄露事件

加密存储

既然明文存储会有安全问题,那就加密存储,一般常用的加密算法是MD5和SHA,当用户注册时,数据库中保存的密码是加密后的密码,当用户登录时先对登录的密码进行MD5,然后和数据库中的密码比对,正确则登录成功,失败则登录失败

结合cookie和session,把登陆流程梳理的清清楚楚

以为这样就足够安全了?其实远远不够,有的人将各种密码的MD5值都算出来,做成一个字典,前面说的泄露的CSDN的密码就是一个很好的素材,这样就可以通过

泄露密码的MD5值->MD5字典->原始的字符串的映射关系,得到泄露的密码,针对这种情况,有2种做法,一种是将密码多次进行MD5,即对加密后的MD5值再次进行MD5,另一种就是加盐

加盐存储

结合cookie和session,把登陆流程梳理的清清楚楚

由于盐值时随机生成的,我们算一下破解一个用户的密码需要多长时间,假如数据库中密码是如此生成的MD5(明文密码+Salt),MD5的方式也被坏人知道了,假如坏人有600w个字典,得先对这些字典加Salt做一次MD5再匹配,而且还有可能匹配不出来,破解一个账号的成本就这么高,而且盐值和密码的方式进行MD5的方式也多种多样啊,Salt可以插中间,Salt倒序再进行MD5。当然还可以这样啊MD5(Salt[0] + 明文密码 + Salt[5])。如果还觉得不够安全,还可以对加盐生成的MD5值再次MD5啊,次数由你定,这样几乎是破解不了

阿里云服务器

编辑该文章

编辑该文章,必须放入您本人的支付宝或微信收款码,通过审核后可,如果浏览者觉得您写的不错了直接对您打赏

复制加密链接

This is a modal dialog!

邮箱

This is a modal dialog!