登录认证-会话技术、JWT令牌、过滤器Filter、拦截器Interceptor

目录

登录认证

登录功能

登录校验

会话技术

会话跟踪方案

Cookie

Session

Token

JWT令牌

JWT令牌-介绍

JWT令牌-生成/解析

过滤器Filter

Filter快速入门

登录校验Filter

令牌校验Filter-流程

Filter执行流程

Filter-拦截路径

Filter-过滤器链

拦截器Intercepter

Intercepter快速入门

令牌校验Intercepter

拦截器-拦截路径

拦截器-执行流程(Filter和Interceptor同时存在的情况下)


登录认证

登录功能

1、构造一个新的类,用于封装登录的结果

java 复制代码
package com.itheima.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data//提供get/set方法
@AllArgsConstructor//提供全参构造
@NoArgsConstructor//提供无参构造
public class LoginInfo {
    //封装登录结果
    private Integer id;
    private String username;
    private String name;
    private String token;
}

三层架构的职责

联调测试

**问题:**在未登录的情况下,我们也可以直接访问部门管理、员工管理等功能

**需求:**只有员工登录成功,才可以访问后台系统中的数据

登录校验

登录校验思路

登录标记:用户登录成功之后,在后续的每一次请求中,都可以获取到该标记。{会话技术}

统一拦截:过滤器Filter、拦截器Intercepter

会话技术

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

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

会话跟踪方案
  • 客户端会话跟踪技术:Cookie
  • 服务端会话跟踪技术:Session
  • 令牌技术
java 复制代码
    //设置Cookie
    @GetMapping("/c1")
    public Result cookie1(HttpServletResponse response){
        response.addCookie(new Cookie("login_username","itheima")); //设置Cookie/响应Cookie
        return Result.success();
    }

    //获取Cookie
    @GetMapping("/c2")
    public Result cookie2(HttpServletRequest request){
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            if(cookie.getName().equals("login_username")){
                System.out.println("login_username: "+cookie.getValue()); //输出name为login_username的cookie
            }
        }
        return Result.success();
    }

**优点:**HTTP协议技术中支持的技术

缺点:

  • 移动端APP无法使用Cookie
  • 不安全,用户可以自己禁用Cookie
  • Cookie不能跨域

跨域区分三个维度:协议、IP/域名、端口

Session
java 复制代码
    @GetMapping("/s1")
    public Result session1(HttpSession session){
        log.info("HttpSession-s1: {}", session.hashCode());

        session.setAttribute("loginUser", "tom"); //往session中存储数据
        return Result.success();
    }

    @GetMapping("/s2")
    public Result session2(HttpSession session){
        log.info("HttpSession-s2: {}", session.hashCode());

        Object loginUser = session.getAttribute("loginUser"); //从session中获取数据
        log.info("loginUser: {}", loginUser);
        return Result.success(loginUser);
    }

**优点:**存储在服务端,安全

缺点:

  • 服务器集群环境下无法直接使用Session
  • Cookie的缺点
Token

优点:

  • 支持PC端、移动端
  • 解决集群环境下的认证问题
  • 减轻服务器端存储压力

**缺点:**需要自己实现

JWT令牌

JWT令牌-介绍
  • 全称:JSON Web Token(https://jwt.io/)
  • 定义了一种简洁的、自包含的格式,用于在通信双方以JSON数据格式安全的传输信息
  • 组成:

=是占位符

令牌的长度不是固定的

JWT令牌-生成/解析
  • 引入jjwt依赖
  • 调用官方提供的工具类Jwts来生成或解析jwt令牌
java 复制代码
/*
* 生成JWT令牌-Jwts.builder()
* */
    @Test
    public void testGenerateJwt(){
        Map<String, Object> dataMap = new HashMap<>();

        String jwt = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, "aXRoZWltYQ==")//指定加密算法/密钥
                .addClaims(dataMap)//添加自定义信息
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24))//设置过期时间
                .compact();//生成令牌

        System.out.println(jwt);
    }
    @Test
    public void testParseJWT(){
        String token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3NjkyNDg4MzF9.zvzVwXx68GyluJbXfhmMEp3RTTOU8h2Vym5BZkgd5AM";
        Claims claims = Jwts.parser()
                .setSigningKey("aXRoZWltYQ==")//指定密钥
                .parseClaimsJws(token)//解析令牌
                .getBody();//获取自定义信息

        System.out.println(claims);
    }

什么时候令牌解析会报错:令牌被篡改、令牌有效期过期了

案例-登录成功后-生成令牌

1、定义JWT令牌操作工具类

2、登录完成后,调用工具类生成JWT令牌,并返回

java 复制代码
package com.itheima.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.Map;

public class JwtUtils {

    // 与测试类一致的密钥
    private static final String SECRET_KEY = "aXRoZWltYQ==";

    // 令牌过期时间:12小时(单位:毫秒)
    private static final long EXPIRATION = 12 * 60 * 60 * 1000L; // 12小时

    /**
     * 生成 JWT 令牌
     *
     * @param claims 自定义载荷(可为 null 或空 Map)
     * @return 生成的 JWT 字符串
     */
    public static String generateToken(Map<String, Object> claims) {
        return Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .addClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
                .compact();
    }

    /**
     * 解析 JWT 令牌
     *
     * @param token 要解析的 JWT 字符串
     * @return 解析后的 Claims 对象
     * @throws RuntimeException 如果 token 无效、过期或签名错误
     */
    public static Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
    }
}

过滤器Filter

  • 概念:Filter过滤器,是JavaWeb三大组件(Servlet、Filter、Listener)之一
  • 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能
  • 过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理
Filter快速入门

1、定义Filter:定义一个类,实现Filter接口,并实现其所有方法

2、配置Filter:Filter类上加@WebFilter注解,配置拦截路径。引导类上加@ServletComponentScan开启Servlet组件支持

java 复制代码
package com.itheima.filter;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

@WebFilter(urlPatterns = "/*")//拦截所有请求
@Slf4j
public class DemoFilter implements Filter {

    //初始化方法,web服务器启动的时候执行,只执行一次
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("init 初始化方法...");
    }
    //拦截到请求之后,执行,会执行多次
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("拦截到了请求...");
        //放行
        filterChain.doFilter(servletRequest, servletResponse);
    }
    //销毁方法,web服务器关闭的时候执行,只执行一次
    @Override
    public void destroy() {
        log.info("destory 销毁方法...");
    }
}
登录校验Filter
令牌校验Filter-流程
java 复制代码
package com.itheima.filter;

import com.itheima.utils.JwtUtils;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
@Slf4j
@WebFilter(urlPatterns = "/*")
public class TokenFilter implements Filter {


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        //1、获取请求路径
        String requestURI = request.getRequestURI();// /employee/login
        /*2、判断是否是登录请求,如果路径中包含/login
        * 说明是登录操作,放行*/
        if (requestURI.contains("/login")) {
            log.info("登录请求,放行");
            filterChain.doFilter(request, response);
            return;
        }
        //3、获取请求头中的token
        String token = request.getHeader("token");
       /* 4、判断token是否存在,如果不存在,说明用户没有登录,
       * 返回错误信息(响应401状态码)*/
        if (token == null || token.isEmpty()) {
            log.info("令牌为空,响应401");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }
      /*  5、如果token存在,校验令牌,如果校验失败
         返回错误信息(响应401状态码)*/
        try{
            JwtUtils.parseToken(token);
        } catch (Exception e) {
            log.info("令牌非法,响应401");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }
        //6、校验通过,放行
        log.info("令牌合法,放行");
        filterChain.doFilter(request, response);
    }
}
Filter执行流程
  • 放行后访问对应资源,资源访问完成后,还会回到Filter中;
  • 如果回到Filter中,会执行放行后的逻辑。
Filter-拦截路径

Filter可以根据需求,配置不同的拦截资源路径

java 复制代码
@WebFilter(urlPatterns = "/*")//拦截所有请求
Filter-过滤器链

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

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

拦截器Intercepter

**概念:**是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,主要用来动态控制拦截器方法的执行

**作用:**拦截请求,在指定方法调用前后,根据业务需要执行预先设定的代码

Intercepter快速入门

1、定义拦截器,实现HandlerIntercepter接口,并实现其所有方法

java 复制代码
package com.itheima.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Component
@Slf4j
public class DemoInterceptor implements HandlerInterceptor {

    //目标资源方法运行之前运行-返回值:true 放行, false 不放行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandle ...");
        return true;
    }
    //目标资源方法运行之后运行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle ...");
    }
    //视图渲染完毕后运行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion ...");
    }
}

2、注册拦截器

java 复制代码
package com.itheima.config;

import com.itheima.interceptor.DemoInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/*
* 配置类
* */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private DemoInterceptor demoInterceptor;
    //注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(demoInterceptor).addPathPatterns("/**");//拦截所有
    }
}
令牌校验Intercepter
java 复制代码
package com.itheima.interceptor;

import com.itheima.utils.JwtUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

/*
* 令牌校验的拦截器
* */
@Slf4j
@Component
public class TokenInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //1、获取请求路径
        String requestURI = request.getRequestURI();// /employee/login
        /*2、判断是否是登录请求,如果路径中包含/login
         * 说明是登录操作,放行*/
        if (requestURI.contains("/login")) {
            log.info("登录请求,放行");
            return true;
        }
        //3、获取请求头中的token
        String token = request.getHeader("token");
        /* 4、判断token是否存在,如果不存在,说明用户没有登录,
         * 返回错误信息(响应401状态码)*/
        if (token == null || token.isEmpty()) {
            log.info("令牌为空,响应401");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
      /*  5、如果token存在,校验令牌,如果校验失败
         返回错误信息(响应401状态码)*/
        try{
            JwtUtils.parseToken(token);
        } catch (Exception e) {
            log.info("令牌非法,响应401");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        //6、校验通过,放行
        log.info("令牌合法,放行");
        return true;
    }



}
拦截器-拦截路径
  • 拦截器可以根据需求,配置不同的拦截路径
java 复制代码
//注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");//拦截所有
    }
拦截器-执行流程(Filter和Interceptor同时存在的情况下)

Filter的拦截范围更大

Filter和Interceptor的区别

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

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

相关推荐
u0104058362 小时前
企业微信外部联系人同步的CDC(变更数据捕获)架构与Java实现
java·架构·企业微信
一条代码鱼2 小时前
修复Nacos namespaces未授权访问漏洞【原理扫描】
java·运维·spring cloud
柳鲲鹏3 小时前
地图影像匹配:基于特征匹配的视觉定位2,python
开发语言·python
努力成为包租婆3 小时前
uniapp--原生插件开发
java·数据库·uni-app
海南java第二人4 小时前
Spring MVC核心流程深度解析:从请求到响应的完美掌控
java·springmvc
未来之窗软件服务4 小时前
幽冥大陆(一百10)PHP打造Java的Jar安全——东方仙盟筑基期
java·php·phar·仙盟创梦ide·东方仙盟
郝学胜-神的一滴4 小时前
深入理解网络IP协议与TTL机制:从原理到实践
linux·服务器·开发语言·网络·网络协议·tcp/ip·程序人生
程序猿_极客7 小时前
【2025 年最新版】Java JDK 安装与环境配置教程(附图文超详细,Windows+macOS 通用)
java·开发语言·windows·macos·jdk