管理用户状态——Cookie与Session

利用Cookie跟踪用户状态

博客系统由多个功能(页面)组成:

  1. 首页——包含博客功能简介、用户列表
  2. 用户博客列表——包含某一用户的文章列表
  3. 文章详细页面——包含某一篇文章的标题、详细内容、创建时间等信息
  4. 创建文章页面——包含文章标题、内容的表单

在创建文章时,除了标题和内容,还需要知道是谁创建的这篇文章,当然我们不能够在表单中添加一个输入框让用户输入自己是谁——因为用户的身份很有可能被伪造。一个办法是在每一个页面被访问之前,我们要求用户输入在网站注册时输入的用户名/密码进行验证,如果验证通过才可以访问对应的页面。HTTP基本认证正好可以完成这样的功能,可是这样实在是太麻烦了,没访问一个页面都需要用户进行输入。

我们知道HTTP协议本身是无状态的,也就是说任何完全一致的请求都将会得到完全相同的返回。但是我们可以认为的在HTTP请求中定义状态。

Cookie是由客户端保存的小型文本文件,其内容为一系列的键值对,在浏览器访问同一个域名的不同页面时,会在HTTP请求中附上Cookie。

Cookie可以保存在内存中(关闭浏览器即消失),也可以保存在硬盘中(到达过期时间后消失)。另外,Cookie也是一个比较古老的东西,与JavaScript同样由网景公司发明,现已被标准化为RFC2109。

我们正是通过Cookie的这些特性来实现用户状态的保存的,每当用户访问一个网站时,服务器程序会分配给它一个唯一的id,这个id就是设置在Cookie中的,以打开浏览器第一次访问http://tianmaying.com为例,因为是打开浏览器后第一次访问,所以请求头中不会有任何网站相关的Cookie存在,这时服务器会随机分配的一个字符串作为用户的id并放在Cookie中:

Set-Cookie:JSESSIONID=9074327855952DA4A296B67685523812; Path=/; HttpOnly

这里没有指定Cookie的过期时间(Expire),那么当浏览器关闭后,Cookie自动失效,从获取网站的Cookie到浏览器关闭的这个周期,被称为一个会话——Session。那么在这个会话中,在同一浏览器中任何一次对tianmaying.com的访问,都会带上这个名字为JSESSIONID(Servlet默认的名字)的Cookie值(在服务器上随机生成的字符串,服务器并会将其保存下来)。

可以简单地这样理解,服务端建立了一个Map<String, Object>,对于每一个请求都可以拿到Cookie中保存的JSESSIONID值,那么服务器程序可以往这个Map里写入任何对象:

map.put(JSESSIONID, <obj>);

那么在这一次会话中,不管是怎样的请求,都可以访问到这个Map中的对象。而服务器保存的这个Map,也被称为Session)。Session是一种服务器端保存用户状态的技术,它最常见的实现方式是在Cookie中加入一个字段存储Session ID;但同时Cookie并不是实现Session的唯一手段,在URL中通过参数来保存Session ID同样也是可行的。

用户登录

在注册用户后,用户需要登录网站来确认自己的身份,登录的方式就是在HTML表单中填入用户名和密码并提交给服务器进行验证。在浏览器的一次Session会话中,Cookie中的JSESSIONID保持不变,所以登录成功(服务器端通过验证)后,我们可以在服务端Session中放入当前的用户对象,这样以后访问任何URL,在对应的JSP/Servlet中都能轻易的拿到它。以下是一个多用户访问的Web应用示意图:

Clipboard Image.png

可以看到,每一个用户都有一个自己的Session。而在JSP/Servlet中,通过API可以很容易的获取到当前用户的Session并将状态信息放入其中。

在Servlet中设置Session属性值

以用户登录为例:

@WebServlet("/account/login")
public class LoginController extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        User user = Data.getByUsername(username);
        if (user == null || !user.getPassword().equals(password)) {
            //登录不成功,返回错误信息
        } else {
            req.getSession().setAttribute("user", user);
            //返回登录成功信息
        }
    }
}

获取Session的API是req.getSession(),接下来通过getAttribute()setAttribute()方法就可以像一个Map一样获取/设置Session的属性值。这里我们将User对象放入了Session,名字为user

在JSP中获取Session属性值

在渲染页面时,很多时候需要获取当前用户的信息,例如导航栏的显示:

  1. 根据用户是否登录显示不同的信息
  2. 如果用户已经登录,需要根据当前用户信息显示某些内容——例如“我的首页”的链接

在JSP Scriptlet中可以通过session对象来获取Session的属性值,如果使用EL表达式,那么需要使用${sessionScope}得到Session对象,下面以导航栏为例:

<div id="navbar" class="navbar-collapse collapse">
  <ul class="nav navbar-nav">
  <c:choose>
    <c:when test="${sessionScope.user != null}">
    <li><a href="userPosts?username=${sessionScope.user.username}">我的首页</a></li>
    <li class="dropdown">
      <a href="#" class="dropdown-toggle" data-toggle="dropdown">管理
        <span class="caret"></span></a>
      <ul class="dropdown-menu">
        <li class="dropdown-header">博客</li>
        <li><a href="#">博客信息</a></li>
        <li><a href="createPost">创建博文</a></li>
        <li><a href="admin/posts">博客文章</a></li>
        <li class="divider"></li>
        <li class="dropdown-header">账号</li>
        <li><a href="#">个人信息</a></li>
        <li><a href="#">更改密码</a></li>
        <li><a href="account/logout">退出</a></li>
      </ul>
    </li>
    <li><a href="account/logout">退出登录</a></li>
    </c:when>
    <c:otherwise>
    <li><a href="account/login">登录</a>
    <li><a href="jsp/register.jsp">注册</a>
    </c:otherwise>
  </c:choose>
  </ul>
</div>

${sessionScope.user != null}作为判断条件表示当前用户已经登录;href="userPosts?username=${sessionScope.user.username}"则是利用当前用户的属性值渲染链接。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值