【Java-Web】利用Session和Filter进行权限管理

目录

1.Cookie

概念

优势和不足

2.Session

3.用Session实现登陆

概念

代码

4.使用Filter实现过滤


        在使用浏览器的时候,浏览器如何保存我们的个人信息呢?有两种方法,一个是Cookie,一个是Session,区别在于,前者是在客户端保存,即我们的电脑或手机等设备上本地保存;后者是在服务器端保存,不需要占用我们本地的空间。两者共同点是都有一个保存期限。比如使用Session的网页,登陆一个网站,第一次登陆之后,可能后面几天不需要再次登录,进去就是自己的页面,但是再过一段时间会提示身份验证过期,需要重新登陆,这就是服务器端的Session保存期限到了,销毁了。

1.Cookie

概念

        cookie的作用是把信息存在客户端,然后通过用户的访问传给服务器。

        如下,第一次访问的时候,客户端向服务器端发送第一次请求request1,服务器端收到之后,返回第一次请求response1,并且返回cookies,expire(cookie的期限)等信息,客户端收到这些信息之后,在本地创建cookies。在后面的一次次request请求中,客户端会携带着cookies一起发送请求,然后服务器端也会更新cookies并返回。

        此外,除了服务器端建立cookies信息,也可以通过JavaScript,在客户端创建cookies。

        如下,通过网页的开发人员工具,可以看到cookie信息。

        也可以看到,在浏览器设置里面的,针对cookie有许许多多的设置。

优势和不足

        cookie是在本地创建,所以不需要占用服务器的资源

        但是与此同时,如果我们清除了本地的cookie,那么它就不存在了。比如,一个使用cookie的网站,第一次登录之后,选择七天免账号密码登陆,然后第二天,我把浏览器的cookie等等数据清除了,清除之后再次登陆,发现不是免账号密码,还是需要重新登陆,这就是因为cookie数据被清除,服务器端无法读取对应信息。

        此外,使用cookie其实安全性并不高,上面说到,cookie可以在客户端修改,那么如果一些别有用心的黑客通过修改cookie来欺骗服务器,对服务器端构成威胁。

        所以,现在很多网站使用cookie不是那么多。

2.Session

        相较cookie,session(会话)的安全性更高。其将信息存储在了服务器端。

        在客户端向服务器端发送request之后,服务器端会返回response,同时返回一个id号,并且在服务器端的内存开辟空间,存储这个id和相关data 。这个id号是标识了当前用户的。在该用户接下来的每一次访问,都会带着这个id,服务器端都会在内存里查找这个id是否存在。而和这个用户相关的信息,也是存储在服务器端。当然,Session也是有时间限制,只要服务器端对应的 id 没有过期,这个会话就还保留着。

        典型的例子是,去网上购物商城买东西,在第一个网店买了本书,加入购物车;第二个网店买鞋子,加入购物车;第三个网店买衣服,加入购物车。最后结算的时候是一起结算的。很明显,访问的是三个不同的网店,但是结帐的时候它怎么会知道我选了哪些商品?明显有一个地方存储我的这些信息,这个地方就是服务器端。

        如下,一次request代表一次请求,一次reponse代表一次返回,而一个会话(Session)是多次请求、返回,反反复复交流才叫一个Session。Session是由很多request和response组成的,而会话的 id 就存在服务器端,对应的信息也存在服务器端。

        这种模型,一方面对于客户端的依赖少了。另一方面,数据存在服务器端,客户端无法修改,安全性更高

3.用Session实现登陆

概念

         在客户端访问的时候,tomcat会自动在服务器端创建一个Session存储相关信息,如下,Actor 1 绑定的 Session 是 1 (圆圈),Actor 2 绑定的 Session 是 2。Session对象和用户的每次访问都是绑定在一起的。

         比如在Session里面创建一个 flag,标记用户是否登陆,如果未登陆就让他登陆,已经登陆,就可以使用网站里的资源,就可以实现我们平常使用的登陆功能。

代码

        创建一个Java类,名字为 LoginServlet.java ,其中的代码如下。

        一些解释也在注释里面。中间用到的UserRepo里面的 auth方法下面放了一张图片。

package cn.edu.swu.inout;

import cn.edu.swu.user.User;
import cn.edu.swu.user.UserRepo;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;

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

    public static final String LOGIN_TOKEN="USER_LOGIN_TOKEN";

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        this.doPost(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String userName = request.getParameter("user");
        String password = request.getParameter("password");


        //这里的逻辑是
        //如果账号密码不为空,那么就直接登陆
        //如果为空,有可能已经登陆,有可能直接没输入,那么看session,session两种情况,一个是有数据,一个是没有数据
        //如果没有数据,那么跳到login.html页面
        //如果有数据,说明之前登陆过,那么直接跳到admin页面
        if (userName != null && password != null) {
            //为什么要有这个判断,因为点了登陆之后,他是跳到login的,即这个loginservlet,所以要在这里有
            this.doLogin(request, response);
        } else {
            HttpSession session = request.getSession();
            if (session == null || session.getAttribute(LoginServlet.LOGIN_TOKEN) != Boolean.TRUE) {
                response.sendRedirect("./login.html");
            } else {
                response.sendRedirect("./admin.html");
            }
        }
    }

    public void doLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String userName = request.getParameter("user");
        String password = request.getParameter("password");

        try {
            User user = UserRepo.getInstance().auth(userName, password);
            if (user != null) {
                HttpSession session=request.getSession();//创建一个session
                session.setAttribute(LOGIN_TOKEN,Boolean.TRUE);//这就相当于flag,标记是否登陆,为true则已经登陆,否则未登录
                response.sendRedirect("./admin.html");
            } else {
                response.sendRedirect("./index.html");
            }
        } catch (SQLException | IOException e) {
            throw new RuntimeException(e);
        }
    }

}

         如下,这个方法就是在数据库里面,通过账号密码 寻找相匹配的用户并返回。

         但是,像这样子些,如果我得到了后台的网页地址,直接输入网址就可以进入,相当于绕过了登陆,并且进行各种操作。这样非常不安全,所以,要使用 Filter 进行过滤。

4.使用Filter实现过滤

        在这里我们进行简单的操作,使用 Filter 对所有资源进行过滤,这样子所有资源都无法直接访问,也包括一些图片资源之类的。当然,像一些图片资源、登陆界面、初始界面等等,可以直接“放行”,不需要对其进行限制。

        除了直接“放行”的资源,其余资源通过Session来判断是否放心。如果没有Session,那么肯定就是未登陆过,就需要登陆。如果有Session,有的网站会一进入就创建Session,所以有两种情况,一种是已经登陆,一种是没有登陆,但是自动创建Session两者区分要用Session里面的flag来判定(flag是上文说过的来标记是否登陆过的信息)。 逻辑和代码如下,由于只是简单模拟,整个逻辑并不特别复杂。

        使用 Filter 进行过滤之后,即使得到了后台网址,也不可以直接访问,要先登录,安全性大大提高。就好比我们平时登陆校园网,如果直接输入同学给的内部链接,不可以直接访问操作界面,跳出来的是登陆界面。

package cn.edu.swu.user;

import cn.edu.swu.inout.LoginServlet;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter("/*")
//这里是所有网页都生效
public class AuthFilter extends HttpFilter {

    public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpSession session = request.getSession();
        System.out.println("auth filter");

        String uri = request.getRequestURI();
        System.out.println(uri);
        if ( uri.endsWith("login.html") || uri.endsWith("index.html") || uri.endsWith("verifyCode") ||
                uri.endsWith("png") || uri.endsWith("jpg") || uri.endsWith("css") || uri.endsWith("login")) {
            chain.doFilter(request, response);
            return;
        }

        if (session == null) {
            System.out.println("auth failed");
            response.sendRedirect("./login.html");
        } else {
            Boolean toke = (Boolean) session.getAttribute(LoginServlet.LOGIN_TOKEN);
            if (toke == Boolean.TRUE) {
                //这里还要判断的原因是,有的网站,即使不登陆也要验证session,所以这里验证一下session里的LOGIN_TOKEN
                //是否为true,为true则是登陆过,否则未登陆过。因为只有之前登陆正确才会设置它
                System.out.println("登录验证成功");
                chain.doFilter(request, response);
            } else {
                System.out.println("auth failed");
                response.sendRedirect("./login.html");
            }
        }
    }

}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力努力再努力.xx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值