• SpringBoot+Session 实现接口验证(过滤器+拦截器)


    需求:只有用户登录成功后,才能访问其它接口,否则提示需要进行登录
    项目仓库地址:https://gitee.com/aiw-nine/springboot_session_verify

    添加pom.xml

    新建Spring Boot(2.7.2)项目,添加如下依赖:

    
    
        4.0.0
        
            org.springframework.boot
            spring-boot-starter-parent
            2.7.2
             
        
        com.aiw
        waimai
        0.0.1-SNAPSHOT
        waimai
        waimai
        
            17
        
        
            
                org.springframework.boot
                spring-boot-starter-web
            
    
            
                org.projectlombok
                lombok
                true
            
    
            
                org.springframework.boot
                spring-boot-starter-test
                test
            
    
            
                com.alibaba
                fastjson
                1.2.76
            
        
    
        
            
                
                    org.springframework.boot
                    spring-boot-maven-plugin
                    
                        
                            
                                org.projectlombok
                                lombok
                            
                        
                    
                
            
        
    
    
    
    • 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

    创建简单的测试接口

    package com.aiw.springboot_session_verify.controller;
    
    import com.aiw.springboot_session_verify.entity.User;
    import com.aiw.springboot_session_verify.response.R;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.Objects;
    
    @RestController
    @RequestMapping("/user")
    public class UserController {
        /**
         * 登录,此处只做简单测试
         *
         * @param user
         * @param request
         * @return
         */
        @RequestMapping(value = "/login", method = RequestMethod.POST)
        public R<User> login(@RequestBody User user, HttpServletRequest request) {
        	// 此处应该和数据库进行交互判断,为做测试,简单写死
            if (Objects.equals(user.getId(), 1) && Objects.equals(user.getName(), "Aiw")) {
                // 登录成功,将id存入session并返回登录成功结果
                request.getSession().setAttribute("user", user.getId());
                request.getSession().setMaxInactiveInterval(1800);  // 设置session失效时间为30分钟
                return R.success("登录成功", user);
            }
            return R.fail("登录失败");
        }
    
        /**
         * 退出登录
         *
         * @param request
         * @return
         */
        @RequestMapping(value = "/logout", method = RequestMethod.POST)
        public R<String> logout(HttpServletRequest request) {
            request.getSession().removeAttribute("user");
            return R.success("退出成功");
        }
    
        /**
         * 此处做测试,看用户在未登录时,能否访问到此接口
         *
         * @return
         */
        @RequestMapping(value = "/index", method = RequestMethod.GET)
        public R<String> index() {
            return R.success("首页,访问成功");
        }
    
    }
    
    • 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

    使用过滤器实现

    创建LoginCheckFilter.java类,实现Filter接口

    package com.aiw.springboot_session_verify.filter;
    
    import com.aiw.springboot_session_verify.response.R;
    import com.alibaba.fastjson.JSON;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.util.AntPathMatcher;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Objects;
    
    /**
     * 检查用户是否已经完成登录(方式一:过滤器)
     * 需要在启动类上加上@ServletComponentScan注解,这样才会扫描@WebFilter注解
     */
    @Slf4j
    @WebFilter
    public class LoginCheckFilter implements Filter {
        // 路径匹配器,支持通配符
        public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            log.info("拦截到的请求:{}", request.getRequestURI());
            // 1、获取本次请求的URI
            String requestURI = request.getRequestURI();
            // 定义不需要处理的请求路径
            String[] urls = new String[]{"/user/login", "/user/logout"};
    
            // 2、判断本次请求是否需要处理
            boolean check = check(urls, requestURI);
    
            // 3、如果不需要处理,则直接放行
            if (check) {
                log.info("本次请求{}不需要处理", requestURI);
                filterChain.doFilter(request, response);
                return;
            }
    
            // 4、判断登录状态,如果已登录,则直接放行
            if (Objects.nonNull(request.getSession().getAttribute("user"))) {
                log.info("用户已登录,用户id为:{}", request.getSession().getAttribute("user"));
                filterChain.doFilter(request, response);
                return;
            }
    
            // 5、如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据
            log.info("用户未登录");
            response.setContentType("application/json; charset=utf-8");
            // 1、使用Fastjson(默认过滤null值)
            response.getWriter().write(JSON.toJSONString(R.error("未登录")));
            // 2、使用默认的Jackson,此处关于Jackson配置的相关属性会失效(即若在配置文件中配置过滤null值,这里返回时不会过滤)
            // response.getWriter().write(new ObjectMapper().writeValueAsString(R.error("未登录")));
            return;
        }
    
        /**
         * 路径匹配,检查本次请求是否需要放行
         *
         * @param urls
         * @param requestURI
         * @return
         */
        public boolean check(String[] urls, String requestURI) {
            for (String url : urls) {
                boolean match = PATH_MATCHER.match(url, requestURI);
                if (match) return true;
            }
            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

    修改启动类

    package com.aiw.springboot_session_verify;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.ServletComponentScan;
    
    @ServletComponentScan
    @SpringBootApplication
    public class SpringbootSessionVerifyApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootSessionVerifyApplication.class, args);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    启动项目,使用ApiPost进行接口测试。首先在未登录状态下,访问/user/index接口
    在这里插入图片描述

    可以看到在未登录时,访问其它接口会失败

    此时先进行登录,访问/user/login接口
    在这里插入图片描述
    再次访问/user/index接口
    在这里插入图片描述

    即登录成功后,可以成功访问该接口;为保证后续操作,此处再访问/user/logout接口,删除后端的session

    使用拦截器实现

    创建LoginCheckInterceptor.java类,实现HandlerInterceptor接口

    package com.aiw.springboot_session_verify.interceptor;
    
    import com.aiw.springboot_session_verify.response.R;
    import com.alibaba.fastjson.JSON;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.servlet.HandlerInterceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import java.util.Objects;
    
    /**
     * 检查用户是否已经完成登录(方式二:拦截器)
     * 需要在实现WebMvcConfigurer接口的配置类中重写addInterceptors方法,将拦截器注册到容器,并指定拦截规则
     */
    @Slf4j
    public class LoginCheckInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            //1.获取请求
            log.info("拦截的请求:{}", request.getRequestURI());
            //2.判断用户是否登录
            HttpSession session = request.getSession();
            // 若存在,则放行
            if (Objects.nonNull(session.getAttribute("user"))) return true;
            //拦截住,并给前端页面返回未登录信息,以输出流的方式,json格式返回
            response.setContentType("application/json; charset=utf-8");
            // 1、使用Fastjson(默认过滤null值)
            response.getWriter().write(JSON.toJSONString(R.error("未登录")));
            // 2、使用默认的Jackson,在配置文件中关于Jackson配置的相关属性会失效
            //response.getWriter().write(new ObjectMapper().writeValueAsString(R.error("未登录")));
            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

    注册拦截器,新建配置类WebConfig.java,实现WebMvcConfigurer接口

    package com.aiw.springboot_session_verify.config;
    
    import com.aiw.springboot_session_verify.interceptor.LoginCheckInterceptor;
    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 {
        /**
         * 注册拦截器
         *
         * @param registry
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new LoginCheckInterceptor())
                    .addPathPatterns("/**")
                    // 排除的请求路径
                    .excludePathPatterns("/user/login", "/user/logout");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    注释掉LoginCheckFilter.java类,再注释掉启动类上的@ServletComponentScan注解,防止过滤器的干扰,启动项目。首先在未登录状态下,访问/user/index接口
    在这里插入图片描述进行登录,访问/user/login接口
    在这里插入图片描述
    再次访问/user/index接口
    在这里插入图片描述

    至此,全部完成,当然后期可以使用Spring Boot+JWT实现接口验证

  • 相关阅读:
    React+Typescript项目环境中搭建并使用redux环境
    人的本能和本性在游戏里表现无疑
    创新型中小企业认定条件有哪些?
    html 常见兼容性问题
    python研究汽车传感器数据统计可视化分析
    手写深度学习之优化器(SGD、Momentum、Nesterov、AdaGrad、RMSProp、Adam)
    腾讯联手警方重拳出击 《绝地求生》外挂首案告破
    [经典面试题]JS的typeof和instanceof区别
    怎么让英文大预言模型支持中文?(一)构建自己的tokenization
    【活动报名】11月19日 | AI GC 的技术与应用构建
  • 原文地址:https://blog.csdn.net/qq_45917176/article/details/126310427