登录校验2.0

news2024/12/26 11:35:44

登录校验2.0

Filter

Filter详解

过滤器Filter在使用中的一些细节,主要介绍一下3个方面的细节:

  1. 过滤器的执行流程
  2. 过滤器的拦截路径配置
  3. 过滤器链
执行流程

img

过滤器当中我们拦截到了请求之后,如果希望继续访问后面的web资源,就要执行放行操作,放行就是调用FilterChain对象当中的doFilter()方法,这个方法之前所编写的代码属于放行之前的逻辑。

在放行后访问完web资源之后还会回到过滤器当中,回到过滤器之后如果有需求还可以执行放行之后的逻辑,放行之后的逻辑写在doFilter()之后。

@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init 初始化方法执行了");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("DemoFilter 放行前逻辑....");
        
        // 放行请求
        chain.doFilter(request, response);

        System.out.println("DemoFilter 放行后逻辑....");
    }

    @Override // 销毁方法,只调用一次
    public void destroy() {
        System.out.println("destory 销毁方法执行了");
    }
}

img

拦截路径

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

拦截路径urlPatterns值含义
拦截具体路径/login只有访问/login路径时,才会被拦截
目录拦截/emps/*访问/emps下的所有资源,都会被拦截
拦截所有/*访问所有资源,都会被拦截

拦截具体路径

@WebFilter(urlPatterns = "/login")
public class DemoFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init 初始化方法执行了");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("DemoFilter 放行前逻辑....");

        // 放行请求
        chain.doFilter(request, response);

        System.out.println("DemoFilter 放行后逻辑....");
    }

    @Override // 销毁方法,只调用一次
    public void destroy() {
        System.out.println("destory 销毁方法执行了");
    }
}

目录拦截

@WebFilter(urlPatterns = "/depts/*")
public class DemoFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init 初始化方法执行了");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("DemoFilter 放行前逻辑....");

        // 放行请求
        chain.doFilter(request, response);

        System.out.println("DemoFilter 放行后逻辑....");
    }

    @Override // 销毁方法,只调用一次
    public void destroy() {
        System.out.println("destory 销毁方法执行了");
    }
}

过滤器链

介绍

过滤器链指的是在一个Web应用程序当中,可以配置多个过滤器,多个过滤器就形成了一个过滤器链

img

比如:在web服务器当中,定义了两个过滤器,这两个过滤器就形成了一个过滤器链。

而这个过滤器链上的过滤器在执行的时候回一个一个的执行,会先执行第一个filter,放行之后再来执行第二个filter,如果执行到了最后一个过滤器放行之后,才会访问对象的web资源。

访问web资源之后,按照过滤器的执行流程,还会回到过滤器当中来执行过滤器放行后的逻辑,而在执行后的逻辑的时候,顺序是反着的。

先执行过滤器2放行之后的逻辑,再来执行过滤器1放行之后的逻辑,在最后在给浏览器响应数据。

验证步骤:

  1. 在filter包下再新建一个Filter过滤器类:AbcFilter
  2. 在AbcFilter过滤器中编写放行前和放行后逻辑
  3. 配置AbcFilter过滤器拦截请求路径为:/*
  4. 重启SpringBoot服务,查看DemoFilter、AbcFilter的执行日志

AbcFilter过滤器

@WebFilter(urlPatterns = "/*")
public class AbcFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Abc 拦截到了请求... 放行前逻辑");

        // 放行
        filterChain.doFilter(servletRequest, servletResponse);

        System.out.println("Abc 拦截到了请求...... 放行后逻辑");
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

打开浏览器访问登录接口

img

注意:以注解方式配置的Filter过滤器,它的执行优先级是按时过滤器类名的自动排序确定的,类名排名越靠前,优先级越高。

如果想让DemoFilter先执行,就需要修改类名

登录校验-Filter

分析

img

登录校验的基本流程:

  • 要进入到后台管理系统,必须先完成登录操作,此时就需要访问登录接口login
  • 登录成功之后,需要在服务端生成一个JWT令牌,并且把JWT令牌返回给前端,前端会将JWT令牌存储下来
  • 在后续的每一次请求当中,都会将JWT令牌携带到服务端,请求到达服务端之后,要想去访问对应的业务功能,此时必须先校验令牌的有效性
  • 对于校验令牌的操作,使用登录校验的过滤器,在过滤器当中来校验令牌的有效性。如果令牌是无效的,就响应一个错误信息,也不会再去放行访问对应的资源。如果令牌存在,并且有效,此时就会放行去访问对应的web资源,执行相应的业务操作。

问题:

  1. 所有请求,拦截到了之后,都需要校验令牌吗?
    • 登录请求例外
  2. 拦截到请求后,什么请求下才可以放行,执行业务操作?
    • 有令牌,且令牌校验通过(合法);否则都返回未登录错误结果。

具体流程

img

基于上面的业务流程,具体的操作步骤:

  1. 获取请求url
  2. 判断请求url中是否包含login,如果包含,说明是登录操作,放行
  3. 获取请求头中的令牌(token)
  4. 判断令牌是否存在,如果不存在,返回错误结果(未登录)
  5. 解析token,如果解析失败,返回错误结果(未登录)
  6. 放行

拦截器Interceptor

介绍

什么是拦截器?

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

作用:

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

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

拦截器的使用步骤分为两步:

  1. 定义拦截器
  2. 注册配置拦截器

自定义拦截器:实现HandlerInterceptor接口,并重写其所有方法

@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        return 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方法:视图渲染完毕后执行,最后执行

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

@Configuration
public class WebConfig implements WebMvcConfigurer {


    // 自定义的拦截器对象
    @Resource
    private LoginCheckInterceptor loginCheckInterceptor;


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

效果如图:

img

如果将拦截器中返回值改为false,再次发送请求后,没有响应数据,说明请求被拦截了没有放行

Interceptor详解

拦截器的使用细节:

  1. 拦截器的拦截路径配置
  2. 拦截器的执行流程

拦截路径

在注册配置拦截器的时候,要指定拦截器的路径,通过addPathOatterns("要拦截路径")方法,就可以指定要拦截哪些资源

/**表示拦截所有资源,而在配置拦截器时,不仅可以指定要拦截哪些资源,还可以指定不拦截哪些资源,只需要调用excludePathPatterns("不拦截路径")方法,指定哪些资源不需要拦截

@Configuration
public class WebConfig implements WebMvcConfigurer {


    // 自定义的拦截器对象
    @Resource
    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

执行流程

img

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

登录校验——Interceptor

登录校验的业务逻辑和登录校验Filter过滤器当中的逻辑是完全一致的。

登录校验拦截器

//自定义拦截器
@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");
 	}
}

当用户没有登录,校验机制返回错误信息,前端页面根据返回的错误信息结果,自动跳转到登录页面

异常处理

当出现异常的时候,并且我们没有做任何异常处理的时候,三层架构处理异常的方案:

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

解决方案:

在三层架构项目中,出现了异常,该如何处理?

  • 方案一:在所有Controller的所有方法中进行try…catch处理
    • 缺点:代码臃肿(不推荐)
  • 方案二:全局异常处理器
    • 好处:简单、优雅(推荐)

img

全局异常处理器

流程:

  • 定义全局异常处理器非常简单,就是定义一个类,在类上加上一个注释@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 // 指定可以捕获哪种类型的异常进行处理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/515802.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内容编排与Kubernetes

第一节 内容编排与Kubernetes 为什么要用k8s 集群环境容器部署的困境,假设我们有数十台服务器。分别部署Nginx,redis,mysql,业务服务。如何合理的分配这些资源。这里就需要用到容器编排 容器编排 在实际集群环境下&#xff0…

线性结构-队列

队列是一种先进先出First In Fisrt Out,FIFO的线性表。 与一般的数组和链表不同,队列要求所有的数据只能从一端进入,从另一端离开。 输入进入的一端叫队尾rear,数据离开的一端叫队头front。 数据只能从队尾进入队列,从队头离开队…

VSCODE配置ROS编译环境

目录 一、安装插件 二、环境配置 2.1初始化工作空间 2.2配置VSCode 2.2.1创建功能包 2.2.2配置 c_cpp_properties.json 2.2.3配置 task.json 2.2.4配置 CMakeLists.txt 三、运行程序 3.1编译程序 3.2启动ros master 3.3执行可执行文件 用VSCode编辑ROS程序时&#xf…

linux 内核内存管理

物理内存 相关数据结构 page(页) Linux 内核内存管理的实现以 page 数据结构为核心,其他的内存管理设施都基于 page 数据结构,如 VMA 管理、缺页中断、RMAP、页面分配与回收等。page 数据结构定义在 include/linux/mm_types.h …

使用 Lambda 函数将 CloudWatch Log 中的日志归档到 S3 桶中

作者:SRE运维博客 博客地址:https://www.cnsre.cn/ 文章地址:https://www.cnsre.cn/posts/221205544069/ 相关话题:https://www.cnsre.cn/tags/aws/ 躺了好久,诈尸了。因为换了工作,所以比较忙一直没有时间…

解决APP抓包问题「网络安全」

1.前言 在日常渗透过程中我们经常会遇到瓶颈无处下手,这个时候如果攻击者从APP进行突破,往往会有很多惊喜。但是目前市场上的APP都会为防止别人恶意盗取和恶意篡改进行一些保护措施,比如模拟器检测、root检测、APK加固、代码混淆、代码反调试…

挖出api接口的重要性

作为一名软件开发者,API是我们工作中不可或缺的一部分。无论是将不同系统连接起来,还是构建多组件应用程序,API都是我们的核心工具之一。在本文中,我们将深入讨论API的技术细节和实际应用。 一.首先,我们来看看什么是…

怎么把mkv格式改成mp4?不妨试试这几种方法吧!

怎么把mkv格式改成mp4?mp4是一种多媒体封装格式,不过我们通常会将它说成是视频格式,它可以在一个文件中容纳无限数量的视频、音频、图片或字幕轨道,mp4格式也是被我们每个人所熟知,因为我们每个人几乎每天都会接触或者…

Spring入门教程

目录 一、Spring最基本的使用 1.创建Maven项目(不需要模板) 2.添加Spring框架支持 3.添加启动类(没啥可说的符合规范即可) 4.创建bean对象 5.将bean对象注册到Spring中 (a)先在resources文件夹中创建一个xml文件(注意:是test文件用了.xml后缀 不是直接创建一个xml文件) (…

[ChatGPT] 从 GPT-3.5 到 GPT-5 的进化之路 | ChatGPT和程序员 : 协作 or 取代

⭐作者介绍:大二本科网络工程专业在读,持续学习Java,努力输出优质文章 ⭐作者主页:逐梦苍穹 ⭐如果觉得文章写的不错,欢迎点个关注一键三连😉有写的不好的地方也欢迎指正,一同进步😁…

FastDFS总结

目录 概述 什么是分布式文件系统 核心概念 目录结构 上传机制 下载机制 Linux中搭建FastDFS 常用指令 SpringBoot整合FastDFS FastDFS集成Nginx 概述 FastDFS是一个开源的轻量级分布式文件系统。它解决了大数据量存储和负载均衡等问题。特别适合以中小文件&#xff…

Android输入法不使用多客户端多屏适配-Android12

Android输入法不使用多客户端多屏适配-Android12 1、IME屏幕之间切换2、属性配置3、屏幕之间切换 IME 窗口 在非默认屏幕上运行的应用 1、IME屏幕之间切换 系统使用一个 IME,但可以在屏幕之间切换,以跟踪用户焦点。Android 10 默认所有第一方和第三方 IM…

【Android】试着写一个资讯界面(含不同板块)

跟着视频做的,并不能动脑子,于是自己顺一遍流程!(只阅读了部分教程,代码不完全相同)(仅为静态界面不含跳转)(在fragment上)此为视频链接 成果图: …

07-HTML-链接标签

<a> 标签定义超链接&#xff0c;用于从一张页面链接到另一张页面。<a> 元素最重要的属性是 href 属性&#xff0c;它指示链接的目标。 属性值描述downloadfilename规定被下载的超链接目标。hrefURL规定链接指向的页面的 URL。pinglist_of_URLs规定以空格分隔的 UR…

YOLOv8 人体姿态估计(关键点检测) python推理 ONNX RUNTIME C++部署

目录 1、下载权重 ​2、python 推理 3、转ONNX格式 4、ONNX RUNTIME C 部署 1、下载权重 我这里之前在做实例分割的时候&#xff0c;项目已经下载到本地&#xff0c;环境也安装好了&#xff0c;只需要下载pose的权重就可以 2、python 推理 yolo taskpose modepredict model…

ESP32设备驱动-PCA9685 LED控制器驱动

PCA9685 LED控制器驱动 文章目录 PCA9685 LED控制器驱动1、PCA9685介绍2、硬件准备3、软件准备4、驱动实现1、PCA9685介绍 PCA9685 是一款 IC 总线控制的 16 通道 LED 控制器,针对红色/绿色/蓝色/琥珀色 (RGBA) 彩色背光应用进行了优化。 每个 LED 输出都有自己的 12 位分辨率…

scala中match使用报错Scala.matchError:(of class java.lang.String)

1.遇到错误 Scala.matchError:(of class java.lang.String) 2.发现问题出在match使用中,如下写法就会报错 val partitionIndex key.toString match {case "chinese" > 0case "math" > 1case "english" > 2} 3.后来修改了写法&#xf…

【大数据学习篇3】HDFS命令操作与MR单词统计

1. HDFS命令使用 [rootmaster bin]# su hd[hdmaster bin]$ #查看/目录[hdmaster bin]$ hdfs dfs -ls / 5 #在/目录创建一个为test名字的文件夹[hdmaster bin]$ hdfs dfs -mkdir /test#查看/目录[hdmaster bin]$ hdfs dfs -ls Found 1 itemsdrwxr-xr-x - hd supergroup …

【rust】| 04——语法基础 | 函数

系列文章目录 【rust】| 00——开发环境搭建 【rust】| 01——编译并运行第一个rust程序 【rust】| 02——语法基础_变量(不可变?)和常量 【rust】| 03——语法基础 | 数据类型 【rust】| 04——语法基础 | 函数 【rust】| 05——语法基础 | 流程控制 文章目录 函数1. 定义函数…

Lecture 15:元学习Meta Learning

目录 Review Machine Learning Introduction of Meta Learning What is Meta Learning? Meta Learning的三个步骤 Meta Learning的framework&#xff1a; ML v.s. Meta Meta Learning的training What is learnable in a learning algorithm? 初始化参数θ0 Optimiz…