五,登录校验

62 阅读5分钟

一,概述

image-20231103110543985

二,会话技术

会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。

会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据

会话跟踪方案:

  • 客户端会话跟踪技术:Cookie
  • 服务端会话跟踪技术:Session
  • 令牌技术

2.1 Cookie

Cookie原理:在浏览器中,Cookie 是服务器让浏览器帮忙携带信息的手段,就像饼干里的纸条,浏览器会储存它,并且在后续的 HTTP 请求中再次发送给服务器

因为Cookie是Http协议支持的技术

  • 服务端通过响应头里面设置Set-Cookie值来将cookie传递给浏览器。

  • 浏览器通过请求头里面的Cookie将cookie值传递给服务端。

image-20231103145530187

跨域区分三个维度:协议、IP地址、域名、端口。只要三个中有任何一个不同,这次请求就是跨域请求。如下图

image-20231103145817384

测试代码:

    @GetMapping("/c1")
    public void cookie1(HttpServletResponse response){
        response.addCookie(new Cookie("userName","zhangsan"));
    }

    //获取客户端发送过来的Cookie
    @GetMapping("/c2")
    public void cookie2(HttpServletRequest request){
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            System.out.println(cookie.getName()+":"+cookie.getValue());
        }
    }

2.2 Session

**Session原理:**存在服务器的一种用来存放用户数据的类哈希表结构

  • 当浏览器第一次发送请求的时候服务器会生成一个hashtable和一个sessionid,sessionid来唯一标识这个hashtable,响应的时候会通过一个响应头set-cookie返回给浏览器,浏览器再将这个sessionid存储在一个名为JESSIONID的cookie中。

  • 浏览器在发送第二次请求时,就会带上这个cookie,这个cookie会存储sessionid一并发]送给了一个服务,服务器再从请求中提取出对应的一个sessionid并和当前保存的所有的一个sessionid去进行一个对比然后找到这个sessionid对应的用户信息。

image-20231103150722082

测试代码:

    //往HttpSession中存储值
    @GetMapping("/s1")
    public void session1(HttpSession session){
        log.info("HttpSession-s1:{}",session.hashCode());
        session.setAttribute("Username","tom");//往session中存储数据
    }
    //从HttpSession中获取值
    @GetMapping("/s2")
    public void session2(HttpServletRequest request){
        HttpSession session = request.getSession();
        log.info("HttpSession-s2:{}",session.hashCode());
        Object username = session.getAttribute("Username");//从session中获取数据
        log.info("username:{}",username);
    }

Cookie是信息存浏览器,Session是将信息存服务端,然后浏览器存sessionId

2.3 令牌token

**令牌原理:**令牌就是用户身份的标识,本质是一串字符串。

  • 当用户登录成功后,服务端会生成一个令牌,将令牌响应给浏览器。
  • 浏览器接收到令牌后将令牌存储起来,在后续每一次请求中,都将这个令牌携带到服务端。
  • 服务端接收到令牌后会校验这个令牌的有效性,如果令牌有效代表用户成功登录了,无效代表用户未登录。
  • 在同一次会话的多次请求之间将共享的数据存储在令牌之中。

image-20231103151041613


2.3.1 JWT令牌介绍

image-20231103151952440

数据由JSON格式变成字符串是通过Base64编码而成的。

  • Base64: 是一种基于64个可打印字符 (A-Z a-z 0-9 + /)来表示二进制数据的编码方式

2.3.2 JWT令牌的生成

  1. 引入jwt令牌的依赖

    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
    
  2. 生成jwt令牌

        @Test
        public void genJwt(){
            Map<String,Object> claims=new HashMap<>();
            claims.put("id",1);
            claims.put("name","tom");
            String jwt = Jwts.builder()
                    .signWith(SignatureAlgorithm.HS256, "admin")//指定签名算法和密钥
                    .setClaims(claims)//自定义内容(载荷部分
                    .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60))//设置jwt令牌有效期
                    .compact();//封装结尾
            System.out.println(jwt);
        }
    

    注意要点:

    1. jwt令牌算法密钥长度最低为4个字符

    2. 高版本jdk会存在找不到包的情况,手动导入

          <dependency>
              <groupId>javax.xml.bind</groupId>
              <artifactId>jaxb-api</artifactId>
              <version>2.3.1</version>
          </dependency>
      

2.3.3 JWT令牌的解析

    @Test
    public void parseJwt(){
        String jwt="eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTY5OTA4MzgyOX0.1p8c09OXoy7Gkrx_hGTbAZ3Ws3HKvlde3Nfd7VetlPM";

        Claims body= Jwts.parser()
                .setSigningKey("admin123")//输入jwt签名密钥
                .parseClaimsJws(jwt)//输入jwt字符串
                .getBody();//获取jwt的数据载荷部分内容。
        System.out.println(body);
    }
  • JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的。
  • 如果JWT令牌解析校验时报错,则说明JWT令牌被篡改或失效了,令牌非法

2.3.4 下发JWT令牌

后端只需要将登录成功后生成的jwt令牌字符串响应给浏览器即可,前端需要将接受到的jwt字符串在之后的每一次请求头header中携带jwt字符串到服务端,请求头的名字为token

三,统一拦截处理

3.1 Filter过滤器

image-20231103223136729

快速入门:

image-20231103223448395

详解:

  1. Filter执行流程:

    image-20231103223755943

  2. Filter的拦截路径

    image-20231103223836885

  3. 过滤器链

    一个web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链

    顺序:注解配置的Filter,优先级是按照过滤器类名字符串的自然排序

    image-20231103223947048

3.2 Interceptor拦截器

image-20231103224633227

Interceptor快速入门:

image-20231103224759023

image-20231103224809366

拦截器Interceptor详解:

  1. 拦截路径

    • 拦截器可以根据需求,配置不同的拦截路径

      image-20231103225004853

    • image-20231103225019712

  2. 执行流程

    image-20231103225104261

3.3 Filter和Interceptor区别

接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现Handlerlnterceptor接口。

拦截范围不同:过滤器Filter会拦截所有的资源,而interceptor只会拦截Spring环境中的资源。