• Springboot 拦截器,拦截所有请求,判断是否登录,验证权限


    Java的三大器

    拦截器的作用

    Java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。

    功能:可以进行权限验证,审计日志等。

    代码实现

    拦截器配置类

    package com.thk.Interceptor;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    /**
     * 拦截器的属性配置
     *
     */
    @Configuration
    public class InterceptorConfiguration implements WebMvcConfigurer {
    
    
        /**
         * 重写addCorsMappings()解决跨域问题
         * 配置:允许http请求进行跨域访问
         *
         * @param registry
         */
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            //指哪些接口URL需要增加跨域设置
            registry.addMapping("/**")
                    //.allowedOrigins("*")//指的是前端哪些域名被允许跨域
                    .allowedOriginPatterns("*")
                    //需要带cookie等凭证时,设置为true,就会把cookie的相关信息带上
                    .allowCredentials(true)
                    //指的是允许哪些方法
                    .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                    //cookie的失效时间,单位为秒(s),若设置为-1,则关闭浏览器就失效
                    .maxAge(3600);
        }
     
        /**
         * 重写addInterceptors()实现拦截器
         * 配置:要拦截的路径以及不拦截的路径
         *
         * @param registry
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            //注册Interceptor拦截器(Interceptor这个类是我们自己写的拦截器类)
            InterceptorRegistration registration = registry.addInterceptor(new Interceptor());
            //addPathPatterns()方法添加需要拦截的路径
            //所有路径都被拦截
            registration.addPathPatterns("/**");
            //excludePathPatterns()方法添加不拦截的路径
            //添加不拦截路径
            registration.excludePathPatterns(
                    //登录
                    "/login",
                    //退出登录
                    "/loginOut",
                    //获取验证码
                    "/getCode",
                    //发送短信
                    "/sendshortMessage",
                    //重置账号
                    "/unsealaccount",
                    //文件上传
                    "/uploadImg",
                    //html静态资源
                    "/**/*.html",
                    //js静态资源
                    "/**/*.js",
                    //css静态资源
                    "/**/*.css"
            );
        }
    }
    
    • 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

    拦截器实现类

    package com.thk.Interceptor;
    
    import com.thk.controller.base.BaseController;
    import com.thk.utils.RedisUtil;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.servlet.HandlerInterceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * 拦截器
     */
    public class Interceptor extends BaseController implements HandlerInterceptor {
    
        @Autowired
        private RedisUtil redisUtil;
    
        /**
         * 在请求处理之前进行调用(Controller方法调用之前)
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
            try {
                //判断是否登录
                boolean verifyPermissions = verifyPermissions(request);
                //判断是否有权限
                boolean competence = competence(request);
                if (verifyPermissions && competence) {
                    return true;
                }
                //这里设置拦截以后重定向的页面,一般设置为登陆页面地址
                response.sendRedirect(request.getContextPath() + "/error.html");
            } catch (Exception e) {
                e.printStackTrace();
            }
            return true;//如果设置为false时,被请求时,拦截器执行到此处将不会继续操作
            //如果设置为true时,请求将会继续执行后面的操作
        }
    }
    
    • 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

    判断是否登录

    1.从请求头中获取token

    2.通过token从redis中获取当前登录对象(object)

    3.判断object是否为空,如果为空就是未登录或者登录时间过期

     /**
         * 验证是否登录
         *
         * @param request
         * @return
         */
        public boolean verifyPermissions(HttpServletRequest request) {
            String token = request.getHeader(Constant.TOKEN);
            Object o = redisUtil.get(token);
            if (o != null) {
                return true;
            }
            return false;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    判断是否有权限

    1.从请求头中获取token

    2.通过token从redis中获取当前登录对象(object)

    3.通过对象查询数据库是否存在当前对象

    4.获取登录对象的登录名 判断是否是(admin或者总经理)这两个账号拥有最高权限

    5.判断是否被授权,(获取临时授权时设置的开始时间,结束时间,当前时间),

    获取这个三个时间的时间戳,判断当前时间是否在开始时间和结束时间之间

    如果开始时间和结束时间为空的话表示当前登录对象未被临时授权,会执行后面的 4,5,6,

    如果有时间,但是当前时间不在这个时间段也会执行 4,5,6

    如果有时间,并且当前时间在这个时间段之中,就会直接返回true

    6.从请求头中获取当前接口的地址,

    7.通过当前登录对象的id查询权限

    8.判断当前登录对象的权限中是否包含当前接口的地址,如果包含,允许当前登录对象访问,如果不包含,则不允许当前登录人访问

     /**
         * 判断是否有权限
         *
         * @param request
         * @return
         */
        public boolean competence(HttpServletRequest request) {
            //获取当前登录对象的全部信息
            People people = peopleMapper.selectById(getUserId(request.getHeader(Constant.TOKEN)));
            //管理员拥有全部权限
            if (Constant.SUPER_ADMIN.equals(people.getUserName())) {
                return true;
            }
            //判断是否被授权
            //防止空指针
            if (people.getStartDate() != null && people.getEndDate() != null) {
                if (dateUtils.ifDate(people.getStartDate(), people.getEndDate(), new Date())) {
                    return true;
                }
            }
            //从请求头中获取的地址
            String requestURI = request.getRequestURI();
            //通过角色id查询当前登陆对象的所有权限
            List list = powerMapper.selectUrl(people.getRoleid());
            ArrayList stringList = new ArrayList<>();
            if (!StringUtils.isEmpty(list)) {
                list.forEach(r -> {
                    stringList.add(r.getUrl());
                });
                return lsitUtils.ifcontainString(stringList, requestURI);
            }
            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

    测试

    1.获取验证码

    2.登录获取token

    (eyJhbGciOiJIUzI1NiJ9eyJqdGkiOiIyMDFlNmY0MS1jM2NhLTRmODItYjAxNC01NWY3ZTU5ZmNkMzgiLCJpYXQiOjE2NTIwNzE1MTMsInN1YiI6InRoayIsImlzcyI6InN0YWZmIiwiZXhwIjoxNjUyMDczMzEzfQunBHUktwyuKpT6D0NDObrPmYGjQ_yU8-lNJ0NbAwHMI)

    3.查询全部用户

    总结:

    避坑问题:

    在拦截器中@autowired注入工具类,或者其他service,mapper会导致空指针异常

    解决方案:

    原因:

    因为拦截器是在spring创建controller之前运行的,这时候这些controller,service,实体类等等这些东西spring并没有去创建,所以会注入失败,并且报空指针异常

    解决方法

    将这个拦截器类也交给spring来进行管理

    1.写一个@bean 来创建拦截器类

    2.在addInterceptors 方法引用中调用这个bean

    3.修改后的代码

    package com.thk.Interceptor;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    /**
     * 拦截器的属性配置
     *
     */
    @Configuration
    public class InterceptorConfiguration implements WebMvcConfigurer {
    
        /**
         * 把Interceptor这个实现类交给spring进行管理-------避坑!!!
         * @return
         */
        @Bean
        Interceptor getAdminInterceptor(){
            return new Interceptor();
        }
    
    
        /**
         * 重写addCorsMappings()解决跨域问题
         * 配置:允许http请求进行跨域访问
         *
         * @param registry
         * @Author 有梦想的肥宅
         */
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            //指哪些接口URL需要增加跨域设置
            registry.addMapping("/**")
                    //.allowedOrigins("*")//指的是前端哪些域名被允许跨域
                    .allowedOriginPatterns("*")
                    //需要带cookie等凭证时,设置为true,就会把cookie的相关信息带上
                    .allowCredentials(true)
                    //指的是允许哪些方法
                    .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                    //cookie的失效时间,单位为秒(s),若设置为-1,则关闭浏览器就失效
                    .maxAge(3600);
        }
     
        /**
         * 重写addInterceptors()实现拦截器
         * 配置:要拦截的路径以及不拦截的路径
         *
         * @param registry
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            //注册Interceptor拦截器(Interceptor这个类是我们自己写的拦截器类)
            InterceptorRegistration registration = registry.addInterceptor(getAdminInterceptor());
            //addPathPatterns()方法添加需要拦截的路径
            //所有路径都被拦截
            registration.addPathPatterns("/**");
            //excludePathPatterns()方法添加不拦截的路径
            //添加不拦截路径
            registration.excludePathPatterns(
                    //登录
                    "/login",
                    //退出登录
                    "/loginOut",
                    //获取验证码
                    "/getCode",
                    //发送短信
                    "/sendshortMessage",
                    //重置账号
                    "/unsealaccount",
                    //文件上传
                    "/uploadImg",
                    //html静态资源
                    "/**/*.html",
                    //js静态资源
                    "/**/*.js",
                    //css静态资源
                    "/**/*.css"
            );
        }
    }
    
    • 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

    4.问题解决

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    力扣(LeetCode)566. 重塑矩阵(C语言)
    多线程原子性、一致性与有序性
    C++STL常用算法合集(上)
    商家中心之java商城 开源java电子商务Spring Cloud+Spring Boot+mybatis+MQ+VR全景+b2b2c
    python学生管理系统-面向对象版
    金仓数据库 KingbaseES 插件参考手册 S (1)
    kafka_2.10启动Kafka broker
    每天一个数据分析题(三百七十九)- 用户留存
    CSDN21天学习挑战赛——Java入门(01)
    React报错之JSX element type does not have any construct or call signatures
  • 原文地址:https://blog.csdn.net/fwdwqdwq/article/details/126114268