• 【登录问题:拦截器和过滤器的应用】


    2. 登录拦截或过滤

    2.1 问题描述

    在项目中,不进行登录验证也可直接进行主页面的访问;

    在过滤器、拦截器中拦截前端发起的请求,判断用户是否已经完成登录;登陆了就放行,如果没有登录则返回提示信息,跳转到登录页面。

    2.2 过滤器

    过滤器具体的处理逻辑如下:

    1. 获取本次请求的URI

    2. 判断本次请求, 是否需要登录, 才可以访问(如果是拦截器,不需要该步骤)

    3. 如果不需要,则直接放行

    4. 判断登录状态,如果已登录,则直接放行

    5. 如果未登录, 则返回未登录结果

    2.2.1 代码实现登录过滤器

    在yml文件中存入放行路径

    excludePath: '/employee/login,/employee/logout,/backend/**,/front/**,favicon.ico'
    
    • 1

    过滤器

    import com.alibaba.fastjson.JSON;
    import com.itheima.reggie.utils.common.BaseContext;
    import com.itheima.reggie.utils.common.R;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.util.AntPathMatcher;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import java.io.IOException;
    import java.util.Arrays;
    
    /**
     * 登录校验
     */
    @WebFilter("/*") // 表示该类是一个filter,拦截所有请求
    @Slf4j
    public class LoginCheckFilter implements Filter {
    
        // 2.2 创建路径匹配器对象
        AntPathMatcher apm = new AntPathMatcher();
    
        @Value("${excludePath}")
        String excludePath;
    
        /**
         * 判断是否登录,并确定是否放行
         *
         * @param filterChain
         * @throws IOException
         * @throws ServletException
         */
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                             FilterChain filterChain) throws IOException, ServletException {
    
            //1. 获取本次请求的URI
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
            String requestURI = req.getRequestURI();
    
            //2. 判断本次请求, 是否需要登录, 才可以访问
            // 2.1 解析要放行的所有请求
            String[] urls = excludePath.split(",");
    
            // 2.3 检查是否在放行范围
            if (checkUrl(urls, requestURI)) {
                //3. 如果不需要,则直接放行
                filterChain.doFilter(request, response);
                return; // 后面代码不需要执行,直接结束
            }
    
            //4. 判断登录状态,如果已登录,则直接放行
            HttpSession session = req.getSession();
            Long employeeId = (Long) session.getAttribute("employee");
    
            if (employeeId != null) {
    
                long id = Thread.currentThread().getId();
                log.info("线程id为:{}",id);
    
                //已经登录,将id存入线程工具类中
                BaseContext.setCurrentId(employeeId);
    
                // 放行
                filterChain.doFilter(request, response);
                return; // 后面代码不需要执行,直接结束
            }
    
            //5. 如果未登录, 则返回未登录结果
            // 前端页面写死的,只识别NOTLOGIN;接受到该符号后,跳转到登录页面
            response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
    
        }
    
        /**
         * 判断某个请求是否在不登录的时候就可以放行
         *
         * @param urls
         * @param requestURI
         * @return
         */
        private boolean checkUrl(String[] urls, String requestURI) {
    
            boolean matchResult = false;
            for (String url : urls) {
    
                // 匹配 本次请求的requestURI  是否符合 url
                matchResult = apm.match(url, requestURI);
    
                if (matchResult) {
                    return true;
                }
            }
    
            log.info("本次请求url为:{},是否需要放行:{}", requestURI, matchResult);
            return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102

    2.2.2 开启组件扫描

    需要在引导类上, 加上Servlet组件扫描的注解, 来扫描过滤器配置的@WebFilter注解, 扫描上之后, 过滤器在运行时就生效了。

    @Slf4j
    @SpringBootApplication
    @ServletComponentScan
    public class ReggieApplication {
        public static void main(String[] args) {
            SpringApplication.run(ReggieApplication.class,args);
            log.info("项目启动成功...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    @ServletComponentScan 的作用:

    在SpringBoot项目中, 在引导类/配置类上加了该注解后, 会自动扫描项目中(当前包及其子包下)的

    ​ @WebServlet ,

    ​ @WebFilter ,

    ​ @WebListener 注解, 自动注册Servlet的相关组件 ;

    2.3 拦截器

    拦截器具体的处理逻辑如下:

    1. 获取本次请求的URI
    2. 判断登录状态,如果已登录,则直接放行
    3. 如果未登录, 则返回未登录结果
    4. 把拦截器配置进容器,并指定拦截规则

    2.3.1 代码实现拦截器

    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.itheima.reggie.utils.common.R;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * 员工登录拦截器
     */
    @Slf4j
    @Component
    public class EmployeeInterceptor implements HandlerInterceptor {
    
        /**
         * 重写preHandle方法,校验登录状态,如果已经登录,则放行;否则跳转到登录页面
         *
         * @param request  请求对象
         * @param response 响应对象
         * @param handler  处理器封装对象
         * @return
         * @throws Exception 1. 获取本次请求的URI
         *                   2. 判断登录状态,如果已登录,则直接放行
         *                   3. 如果未登录, 则返回未登录结果
         *                   4. 把拦截器配置进容器,并指定拦截规则
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            // 1. 获取本次请求的URI
            String requestURI = request.getRequestURI();
    
            // 2. 放行不需要拦截的资源  /employee/login
            /* if ("/employee/login".equals(requestURI)) {
                return true;
            } */
            log.info("本次请求URI:{}", requestURI);
            Long employeeId = (Long) request.getSession().getAttribute("employee");
            // 3. 如果未登录, 则返回未登录结果
            if (employeeId == null) {
    
                // 前端跳转到登录页面,需要用到用到一个特殊标识:NOTLOGIN
                // 因为preHandle返回值类型为boolean,所以不能return RObj
                // 使用response原生API
                // 创建R对象,并且手动序列化为JSON格式字符串
    
                /**
                 * writeValueAsString(obj)  把obj序列化为JSON格式字符串
                 * writeValue(writer, obj)  把obj序列化为JSON格式字符串,然后写入writer
                 */
                new ObjectMapper().writeValue(response.getWriter(), R.error("NOTLOGIN"));
    
                // 拦截
                return false;
            }
    
            // 4. 判断登录状态,如果已登录,则直接放行
            // 放行
            return true;
    
            // 5. 把拦截器配置进容器,并指定拦截规则
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    2.3.2 web容器中配置拦截器

    在配置文件写入要排除的路径

    excludePath: '/employee/login,/employee/logout,/backend/**,/front/**,/employee/login,favicon.ico'
    
    • 1

    web初始化配置配置要拦截的路径

    import com.itheima.reggie.web.interceptor.EmployeeInterceptor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
    
    import java.util.Arrays;
    
    @Slf4j
    @Configuration
    public class WebMvcConfig extends WebMvcConfigurationSupport {
    
        @Autowired
        EmployeeInterceptor employeeInterceptor;
    
        @Value("${excludePath}")
        String excludePath;
    
        /**
         * 配置拦截器,并映射拦截路径
         *
         * @param registry
         */
        @Override
        protected void addInterceptors(InterceptorRegistry registry) {
            log.info("开始加载拦截器...");
            String[] urls = excludePath.split(",");
            log.info("直接放行的路径是:{}", Arrays.toString(urls));
            registry
                    .addInterceptor(employeeInterceptor)
                    // 本拦截器拦截的资源路径
                    .addPathPatterns("/employee/**")
                    // 本拦截器不拦截的资源路径
                    // .excludePathPatterns("/employee/login");
                    .excludePathPatterns(urls);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
  • 相关阅读:
    Backtrader官方中文文档
    FTP传输安全问题日渐突出,如何解决替代问题?
    深度学习中的epoch, batch 和 iteration
    直播课堂系统03-model类及实体
    GB/T 40623-2021 船用防静电升高地板检测
    首次开通社交账号亲自招聘人才 周星驰都在关注的Web3 你知道是什么吗?
    Vue09/Vue 编程式导航 query传参 params传参 之间使用区别、route和router区别原理
    基于基于全局差错能量函数的双目图像立体匹配算法matlab仿真,并提取图像的深度信息
    Linux 命令学习 -磁盘分区和格式化
    12 Python正则表达式
  • 原文地址:https://blog.csdn.net/weixin_50707328/article/details/126950274