在访问网站时,常常需要进行权限校验,从而决定用户是否能够正常访问。可以使用过滤器或拦截器加session来实现。本文使用HandlerInterceptor拦截器实现登录校验。

创建拦截器

创建拦截器的基本流程:

1. 创建一个拦截器类实现HandlerInterceptor接口,重写其preHandle方法
     (拦截作用主要由preHandle实现)
   2. 在配置类中对该拦截器进行配置
     (哪些地址拦截,哪些地址不拦截)

1. 生成拦截器类

@Slf4j
@Component
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        log.info("拦截到请求:{}", request.getRequestURI() + "    拦截器" + this.getClass().getSimpleName());
        HttpSession session = request.getSession();

        // 如果是来自后台的请求  (请求地址包含 employee,来自EmployeeController)
        if (request.getRequestURI().contains("employee")){
            boolean isHave = !(session.getAttribute("employeeInfo") == null);
            if (!isHave) {
                log.info("用户未登录");
                response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
            }
            return isHave;
            // 如果是来自客户端的请求  (请求地址包含 user,来自UserController)
        } else if (request.getRequestURI().contains("user")) {
            Object userInfom = request.getSession().getAttribute("userInfo");
            boolean isHave = !(userInfom == null);
            if (!isHave) {
                log.info("用户未登录");
                response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
            }
            return isHave;
        }

        return false;

    }
}

preHandle方法返回true表示放行,false不放行

2. 配置拦截器

@Slf4j
@Configuration
public class WebMVCConfig extends WebMvcConfigurationSupport {

    @Autowired
    private MyInterceptor myInterceptor;

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        // addPathPatterns  用于添加拦截规则
        // excludePathPatterns  排除拦截
        registry.addInterceptor(myInterceptor).addPathPatterns("/**").
                excludePathPatterns("/employee/login", "/employee/logout", "/backend/**", "/front/**", "/user/login");
    }
}

其中,backend和front里面放的是一些静态资源,网页和图片等,它们被解除了拦截。静态资源本身不需要被拦截,真正要拦截的是针对controller的请求,如http://xxx:8080/employee/list。拦截了针对controller的请求,即使静态资源能访问也没有关系,无法通过请求拿到数据。

这个WebMVCConfig类专门进行web相关的一些配置,比如路径映射配置等。

编写Controller层

现在拦截器已经配置好了,开始进行controller层的编写(login和logout)

其中login的主要逻辑为

根据请求封装的用户对象,按其属性值为条件(这里主要是username和password),进行查询
	
	if (没查到) {
		返回R对象(失败信息);
	} else (查到) {
	    session保存用户信息;
	    返回R对象(用户对象);
	}

logout主要就是对session中的数据进行清除

下面是controller代码

@Slf4j
@RequestMapping("/employee")
@RestController
public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;

    @PostMapping("/login")
    public R<Employee> login(@RequestBody Employee employee, HttpSession session){

        // 对密码加密处理
        String password = DigestUtils.md5DigestAsHex(employee.getPassword().getBytes());

        // 查询条件:根据输入的username和password查询,且status为1
        LambdaQueryWrapper<Employee> employeeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        employeeLambdaQueryWrapper.like(employee.getUsername() != null, Employee::getUsername, employee.getUsername());
        employeeLambdaQueryWrapper.like(employee.getPassword() != null, Employee::getPassword, password);
        employeeLambdaQueryWrapper.eq(Employee::getStatus, 1);
        Employee employeeQuery = employeeService.getOne(employeeLambdaQueryWrapper);

        if (employeeQuery == null) {
            return R.error("登陆失败");
        }

        // 向session保存数据,供拦截器检查
        session.setAttribute("employeeInfo", employeeQuery.getUsername());
        return R.success(employeeQuery);

    }


    @PostMapping("/logout")
    public R logout(HttpSession session){
        // 清除 Session
        session.removeAttribute("employeeInfo");
        return R.success("退出成功");
    }

这里拦截器进行拦截跳转回登录界面、登录后跳转到系统首页,均由前端实现。

登录成功进入首页:

methods: {
        async handleLogin() {
          this.$refs.loginForm.validate(async (valid) => {
            if (valid) {
              this.loading = true
              let res = await loginApi(this.loginForm)
              if (String(res.code) === '1') {
                localStorage.setItem('userInfo',JSON.stringify(res.data))
                window.location.href= '/backend/index.html'
              } else {
                this.$message.error(res.msg)
                this.loading = false
              }
            }
          })
        }
      }

拦截返回登录界面:

service.interceptors.response.use(res => {
      if (res.data.code === 0 && res.data.msg === 'NOTLOGIN') {// 返回登录页面     NOTLOGIN
        console.log('---/backend/page/login/login.html---')
        localStorage.removeItem('userInfo')
        window.top.location.href = '/backend/page/login/login.html'
      } else {
        return res.data
      }
    },

如此,便实现了SpringBoot项目利用拦截器进行登录校验。