首页 > 其他分享 >理解Web登录机制:会话管理与跟踪技术解析(四)-拦截器Interceptor、异常处理

理解Web登录机制:会话管理与跟踪技术解析(四)-拦截器Interceptor、异常处理

时间:2024-11-08 12:45:40浏览次数:3  
标签:Web 拦截器 depts public Interceptor 执行 异常 拦截

本文将详细探讨如何通过拦截器实现登录校验,并介绍如何通过异常处理来确保系统的鲁棒性。我们将通过具体的示例,深入分析如何在Spring框架中配置拦截器与异常处理,以便为开发者提供一套高效、安全的登录校验和异常管理方案。

目录

前言

拦截器Interceptor

快速入门

Interceptor详解

拦截路径

执行流程

登录校验- Interceptor

异常处理

当前问题

解决方案

全局异常处理器

总结


前言

本文将详细探讨如何通过拦截器实现登录校验,并介绍如何通过异常处理来确保系统的鲁棒性。我们将通过具体的示例,深入分析如何在Spring框架中配置拦截器与异常处理,以便为开发者提供一套高效、安全的登录校验和异常管理方案。


拦截器Interceptor

快速入门

什么是拦截器?

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

拦截器的作用:

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

在拦截器当中,我们通常也是做一些通用性的操作,比如:我们可以通过拦截器来拦截前端发起的请求,将登录校验的逻辑全部编写在拦截器当中。在校验的过程当中,如发现用户登录了(携带JWT令牌且是合法令牌),就可以直接放行,去访问spring当中的资源。如果校验时发现并没有登录或是非法令牌,就可以直接给前端响应未登录的错误信息。

下面我们通过快速入门程序,来学习下拦截器的基本使用。拦截器的使用步骤和过滤器类似,也分为两步:
1. 定义拦截器
2. 注册配置拦截器
自定义拦截器:实现HandlerInterceptor接口,并重写其所有方法

//自定义拦截器
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
    //目标资源方法执行前执行。 返回true:放行 返回false:不放行
    @Override
    public boolean preHandle(HttpServletRequest request,
    HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle .... ");
        return true; //true表示放行
     }
    //目标资源方法执行后执行
    @Override
    public void postHandle(HttpServletRequest request,
    HttpServletResponse response, Object handler, ModelAndView
    modelAndView) throws Exception {
        System.out.println("postHandle ... ");
     }
    //视图渲染完毕后执行,最后执行
    @Override
    public void afterCompletion(HttpServletRequest request,
    HttpServletResponse response, Object handler, Exception ex) throws
    Exception {
        System.out.println("afterCompletion .... ");
     }
}

注意:
preHandle方法:目标资源方法执行前执行。 返回true:放行 返回false:不放行
postHandle方法:目标资源方法执行后执行
afterCompletion方法:视图渲染完毕后执行,最后执行

注册配置拦截器:实现WebMvcConfigurer接口,并重写addInterceptors方法

@Configuration
public class WebConfig implements WebMvcConfigurer {
    //自定义的拦截器对象
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册自定义拦截器对象
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**
        ");//设置拦截器拦截的请求路径( /** 表示拦截所有请求)
     }
}

将拦截器中返回值改为false
使用postman,再次点击send发送请求后,没有响应数据,说明请求被拦截了没有放行。

 

Interceptor详解

拦截器的使用细节我们主要介绍两个部分:
1. 拦截器的拦截路径配置
2. 拦截器的执行流程

拦截路径

首先我们先来看拦截器的拦截路径的配置,在注册配置拦截器的时候,我们要指定拦截器的拦截路径,通过 addPathPatterns("要拦截路径") 方法,就可以指定要拦截哪些资源。
在入门程序中我们配置的是 /** ,表示拦截所有资源,而在配置拦截器时,不仅可以指定要拦截哪些资源,还可以指定不拦截哪些资源,只需要调用 excludePathPatterns("不拦截路径") 方法,指定哪些资源不需要拦截。

@Configuration
public class WebConfig implements WebMvcConfigurer {
    //拦截器对象
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册自定义拦截器对象
        registry.addInterceptor(loginCheckInterceptor)
         .addPathPatterns("/**")//设置拦截器拦截的请求路径( /**
        表示拦截所有请求)
         .excludePathPatterns("/login");//设置不拦截的请求路径
     }
}

在拦截器中除了可以设置 /** 拦截所有资源外,还有一些常见拦截路径设置:

拦截路径含义举例
/* 一级路径能匹配/depts,/emps,/login,不能匹配
/depts/1
/**任意级路径 能匹配/depts,/depts/1,/depts/1/2
/depts/*/depts下的一级路
能匹配/depts/1,不能匹配/depts/1/2,/depts
/depts/**/depts下的任意级
路径
能匹配/depts,/depts/1,/depts/1/2,不能匹
配/emps/1

下面主要来演示下 /** 与 /* 的区别:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    //拦截器对象
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册自定义拦截器对象
        registry.addInterceptor(loginCheckInterceptor)
         .addPathPatterns("/*")
         .excludePathPatterns("/login");//设置不拦截的请求路径
     }
}

控制台没有输出拦截器中的日志信息,说明 /* 没有匹配到拦截路径 /emp/1 。

执行流程

介绍完拦截路径的配置之后,接下来我们再来介绍拦截器的执行流程。通过执行流程,大家就能够清晰的知道过滤器与拦截器的执行时机。

  • 当我们打开浏览器来访问部署在web服务器当中的web应用时,此时我们所定义的过滤器会拦截到这次请求。拦截到这次请求之后,它会先执行放行前的逻辑,然后再执行放行操作。而由于我们当前是基于springboot开发的,所以放行之后是进入到了spring的环境当中,也就是要来访问我们所定义的controller当中的接口方法。
  • Tomcat并不识别所编写的Controller程序,但是它识别Servlet程序,所以在Spring的Web环境中提供了一个非常核心的Servlet:DispatcherServlet(前端控制器),所有请求都会先进行到DispatcherServlet,再将请求转给Controller。
  • 当我们定义了拦截器后,会在执行Controller的方法之前,请求被拦截器拦截住。执行preHandle() 方法,这个方法执行完成后需要返回一个布尔类型的值,如果返回true,就表示放行本次操作,才会继续访问controller中的方法;如果返回false,则不会放行(controller中的方法也不会执行)。
  • 在controller当中的方法执行完毕之后,再回过来执行 postHandle() 这个方法以及afterCompletion() 方法,然后再返回给DispatcherServlet,最终再来执行过滤器当中放行后的这一部分逻辑的逻辑。执行完毕之后,最终给浏览器响应数据。

演示下过滤器和拦截器同时存在的执行流程:

@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request,
    HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle .... ");
        return true; //true表示放行
     }
    @Override
    public void postHandle(HttpServletRequest request,
    HttpServletResponse response, Object handler, ModelAndView
    modelAndView) throws Exception {
        System.out.println("postHandle ... ");
     }
    @Override
    public void afterCompletion(HttpServletRequest request,
    HttpServletResponse response, Object handler, Exception ex) throws
    Exception {
        System.out.println("afterCompletion .... ");
     }
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
    //拦截器对象
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册自定义拦截器对象
        registry.addInterceptor(loginCheckInterceptor)
         .addPathPatterns("/**")//拦截所有请求
         .excludePathPatterns("/login");//不拦截登录请求
     }
}

开启DemoFilter过滤器

@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest,
    ServletResponse servletResponse, FilterChain filterChain) throws
    IOException, ServletException {
        System.out.println("DemoFilter 放行前逻辑.....");
        //放行请求
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("DemoFilter 放行后逻辑.....");
     }
}

 以上就是拦截器的执行流程。通过执行流程分析,大家应该已经清楚了过滤器和拦截器之间的区别,其实它们之间的区别主要是两点:

  • 接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口。
  • 拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。

登录校验- Interceptor

登录校验拦截器

//自定义拦截器
@Component //当前拦截器对象由Spring创建和管理
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
    //前置方式
    @Override
    public boolean preHandle(HttpServletRequest request,
    HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle .... ");
        //1.获取请求url
        //2.判断请求url中是否包含login,如果包含,说明是登录操作,放行
        //3.获取请求头中的令牌(token)
        String token = request.getHeader("token");
        log.info("从请求头中获取的令牌:{}",token);
        //4.判断令牌是否存在,如果不存在,返回错误结果(未登录)
        if(!StringUtils.hasLength(token)){
            log.info("Token不存在");
            //创建响应结果对象
            Result responseResult = Result.error("NOT_LOGIN");
            //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的
            用于实现对象和json的转换工具类)
            String json = JSONObject.toJSONString(responseResult);
            //设置响应头(告知浏览器:响应的数据类型为json、响应的数据编码
            表为utf-8)
            response.setContentType("application/json;charset=utf-
            8");
            //响应
            response.getWriter().write(json);
            return false;//不放行
         }
        //5.解析token,如果解析失败,返回错误结果(未登录)
        try {
            JwtUtils.parseJWT(token);
         }catch (Exception e){
            log.info("令牌解析失败!");
            //创建响应结果对象
            Result responseResult = Result.error("NOT_LOGIN");
            //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的
            用于实现对象和json的转换工具类)
            String json = JSONObject.toJSONString(responseResult);
            //设置响应头
            response.setContentType("application/json;charset=utf-
            8");
            //响应
            response.getWriter().write(json);
            return false;
         }
            //6.放行
        return true;
     }
}

注册配置拦截器

@Configuration
public class WebConfig implements WebMvcConfigurer {
    //拦截器对象
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册自定义拦截器对象
        registry.addInterceptor(loginCheckInterceptor)
         .addPathPatterns("/**")
         .excludePathPatterns("/login");
     }
}

异常处理

当前问题

我们打开浏览器,访问系统中的新增部门操作,系统中已经有了 "就业部" 这个部门,我们再来增加一个就业部,看看会发生什么现象。

点击确定之后,窗口关闭了,页面没有任何反应,就业部也没有添加上。 而此时,大家会发现,网络请求报错了。

上述错误信息的含义是,dept部门表的name字段的值 就业部 重复了,因为在数据库表dept中已经有了就业部,我们之前设计这张表时,为name字段建议了唯一约束,所以该字段的值是不能重复的。而当我们再添加就业部,这个部门时,就违反了唯一约束,此时就会报错。

 响应回来的数据是一个JSON格式的数据。但这种JSON格式的数据还是我们开发规范当中所提到的统一响应结果Result吗?显然并不是。由于返回的数据不符合开发规范,所以前端并不能解析出响应的JSON数据。
接下来我们需要思考的是出现异常之后,当前案例项目的异常是怎么处理的?
答案:没有做任何的异常处理

  • Mapper接口在操作数据库的时候出错了,此时异常会往上抛(谁调用Mapper就抛给谁),会抛给service。
  • service 中也存在异常了,会抛给controller。
  • 而在controller当中,我们也没有做任何的异常处理,所以最终异常会再往上抛。最终抛给框架之后,框架就会返回一个JSON格式的数据,里面封装的就是错误的信息,但是框架返回的JSON格式的数据并不符合我们的开发规范。

解决方案

那么在三层构架项目中,出现了异常,该如何处理?
方案一:在所有Controller的所有方法中进行try…catch处理
缺点:代码臃肿(不推荐)
方案二:全局异常处理器
好处:简单、优雅(推荐)

全局异常处理器

  • 定义全局异常处理器非常简单,就是定义一个类,在类上加上一个注解@RestControllerAdvice,加上这个注解就代表我们定义了一个全局异常处理器。
  • 在全局异常处理器当中,需要定义一个方法来捕获异常,在这个方法上需要加上注解@ExceptionHandler。通过@ExceptionHandler注解当中的value属性来指定我们要捕获的是哪一类型的异常。
@RestControllerAdvice
public class GlobalExceptionHandler {
    //处理异常
    @ExceptionHandler(Exception.class) //指定能够处理的异常类型
    public Result ex(Exception e){
        e.printStackTrace();//打印堆栈中的异常信息
        //捕获到异常之后,响应一个标准的Result
        return Result.error("对不起,操作失败,请联系管理员");
     }
}

@RestControllerAdvice = @ControllerAdvice + @ResponseBody
处理异常的方法返回值会转换为json后再响应给前端

此时,我们可以看到,出现异常之后,异常已经被全局异常处理器捕获了。然后返回的错误信息,被前端程序正常解析,然后提示出了对应的错误提示信息。

 以上就是全局异常处理器的使用,主要涉及到两个注解:

  • @RestControllerAdvice //表示当前类为全局异常处理器
  • @ExceptionHandler //指定可以捕获哪种类型的异常进行处理


总结

总的来说,登录校验、拦截器和异常处理是保证系统安全性和稳定性的重要措施。在实际开发中,合理运用这些机制,不仅能够有效保护用户数据和系统资源,还能提升系统的健壮性与可维护性。通过本文的探讨,希望开发者能够更加清晰地理解如何实现一个高效、安全、易扩展的登录校验体系。

标签:Web,拦截器,depts,public,Interceptor,执行,异常,拦截
From: https://blog.csdn.net/m0_63267251/article/details/143610435

相关文章

  • 11.8 javaweb学习 day1 入门
    网页响应流程浏览器前端服务器后端服务器数据库1.浏览器请求前端2.前端响应浏览器3.浏览器请求后端4.后端请求数据库5.数据库响应后端6.后端响应浏览器网页的组成1.网页的文字,图片,音频,视频,超链接什么的,本质是前端代码2.前端代码通过浏览器的转化......
  • EHOME视频平台EasyCVR视频融合平台使用OBS进行RTMP推流,WebRTC播放出现抖动、卡顿如何
    在现代视频监控领域,跨区域的网络化视频监控管理平台成为了大中型项目的首选。EHOME视频平台EasyCVR以其强大的功能和兼容性,成为了众多项目的核心组件。它不仅能够管理视频资源、设备、用户、运维和安全,还支持多种行业标准协议,包括GB28181、GB35114、RTSP/Onvif、RTMP、JT808、GA/T......
  • 36套Web前端全栈Vue3项目实战P7架构-入门篇+项目篇+进阶篇+架构篇
    36套Web前端全栈Vue3项目实战P7架构-入门篇+项目篇+进阶篇+架构篇36套eb前端全栈Vue3项目实战-入门篇+项目篇+进阶篇+架构篇,P7前端架构,高薪面试,Vue3源码剖析视频课程-技术栈-TypeScript+Vute+ElementPlus+Koa2+Node.js+Pinia+EChart4.0+Uni-App+React18+Flutter+Web3D+Vant+UI,项......
  • PHP与Vue.js结合,开发现代Web应用的前后端分离
    随着前端技术的迅猛发展,前后端分离已成为现代Web应用开发的重要趋势。在这个架构中,PHP作为后端语言,配合Vue.js这样的前端框架,可以有效提高开发效率和用户体验。PHP与Vue.js的结合,使得开发者能够专注于各自领域的专业技术,形成高效、灵活的开发模式。PHP作为一种成熟的后端开发语言......
  • 使用 React Native WebView 实现 App 与 Web 的通讯
    使用ReactNativeWebView实现App与Web的通讯在移动应用开发中,常常需要在应用中嵌入网页,并实现App与Web之间的通讯。ReactNative提供了一个强大的组件——react-native-webview,可以帮助我们实现这一功能。在这篇文章中,我们将介绍如何使用react-native-webview......
  • CTF-WEB-需要管理员
    首页打开链接进入发现404使用dirsearch 扫描一下,发现/robots.txt泄露进入到其中进行查看,发现/resusl.php进入到该页面,页面显示:Warning:你不是管理员你的IP已经被记录到日志了,但是下方提示if($_GET[x]==$password),就是需要传入一个参数x,并且x的值要等于password根......
  • (附项目源码)python开发语言,基于python Web的高校毕业论文管理系统 51,计算机毕设程序开
    摘 要随着信息化技术的迅速发展,人类信息化文明的到来,为人类的日常生活以及日常生产活动提供了非常大的便利,有效地解决了很多曾经无法解决的问题。本次基于pythonWeb的高校毕业论文管理系统的开发是针对我国传统的高校毕业论文管理模式沟通成本高且容易造成管理混乱、导师......
  • 网络安全工程师必知的WEB知识
    作为一名网络安全工程师,尤其是WEB渗透测试工程师,必须掌握一些WEB相关的基础知识,下面重点从WEB服务架构、浏览器请求过程、服务器操作系统、WEB应用服务器、数据库系统、动态网站脚本语言、WEB前端框架等。1.Web服务架构Web服务主要分为C/S架构和B/S架构。下面做一下分别......
  • 源码开放:WebSocket应用示例
    1WebSocket概述WebSocket是HTML5下一种新的协议(本质上是一个基于TCP的协议),它实现了浏览器与服务器之间的全双工通信,能够节省服务器资源和带宽,达到实时通讯的目的。WebSocket协议通过握手机制,允许客户端和服务器之间建立一个类似TCP的连接,从而方便它们之间的通信。在线......
  • 移动Web前端高效开发实战:HTML 5 + CSS 3 + JavaScript + Webpack + React Native + Vu
    书:pan.baidu.com/s/1tIHXj9HmIYojAHqje09DTA?pwd=jqsoHTML5新特性与应用:介绍HTML5的新特性,包括语义化标签、本地存储、设备兼容、连接特性等,并讲解如何在移动Web前端开发中充分利用这些特性提升用户体验。CSS3样式与动画设计:详细讲解CSS3的样式设计和动画效果,包括选择器、盒......