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

2年前 (2022) 程序员胖胖胖虎阿
174 0 0

Java的三大器

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

拦截器的作用

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"
        );
    }
}

拦截器实现类

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.从请求头中获取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.从请求头中获取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<Power> list = powerMapper.selectUrl(people.getRoleid());
        ArrayList<String> stringList = new ArrayList<>();
        if (!StringUtils.isEmpty(list)) {
            list.forEach(r -> {
                stringList.add(r.getUrl());
            });
            return lsitUtils.ifcontainString(stringList, requestURI);
        }
        return false;
    }

测试

1.获取验证码

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

 2.登录获取token

(eyJhbGciOiJIUzI1NiJ9eyJqdGkiOiIyMDFlNmY0MS1jM2NhLTRmODItYjAxNC01NWY3ZTU5ZmNkMzgiLCJpYXQiOjE2NTIwNzE1MTMsInN1YiI6InRoayIsImlzcyI6InN0YWZmIiwiZXhwIjoxNjUyMDczMzEzfQunBHUktwyuKpT6D0NDObrPmYGjQ_yU8-lNJ0NbAwHMI)

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

 3.查询全部用户

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

总结:

避坑问题:

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

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

 解决方案:

原因:

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

解决方法

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

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

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

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

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

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"
        );
    }
}

4.问题解决

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

相关文章

暂无评论

暂无评论...