在请求被处理前,执行一些公共逻辑,例如检查用户是否认证、是否有权限访问受保护的资源、日志记录等; 可以在请求被处理前,对请求的数据进行预处理,还可以对返回的结果进行统一处理。

1、Cors跨域处理

在项目中创建config文件包,然后创建WebConfig类,代码如下:

 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
package com.example.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    /**
     * 添加跨域资源共享(CORS)映射配置
     * 该方法用于配置允许从哪些域对资源进行跨域请求
     *
     * @param registry CorsRegistry对象,用于注册CORS映射
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 配置跨域请求的映射路径,"/**"表示匹配所有路径
        registry.addMapping("/**")
                // 配置允许跨域请求的源,此处为本地开发环境地址
                .allowedOrigins("http://localhost:5173")
                // 允许在请求中携带凭证(如Cookies)
                .allowCredentials(true)
                // 配置允许的请求头,"*"表示允许所有请求头
                .allowedHeaders("*")
                // 配置允许的HTTP方法,此处允许GET、POST和DELETE请求
                .allowedMethods("GET", "POST", "DELETE");
    }
}

2、登录校验

1、创建拦截器

定义一个类并实现HandlerInterceptor接口。

可以根据需求实现接口中的三个方法:preHandle(在请求处理之前调用)、postHandle(在请求处理之后,但在视图渲染之前调用)和afterCompletion(在整个请求结束之后调用)

项目config文件下创建LoginInterceptor类,代码如下:

 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
package com.example.demo.config;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    /**
     * 在请求处理之前进行预处理
     *
     * @param request 	HttpServletRequest对象,包含请求相关的信息
     * @param response 	HttpServletResponse对象,用于响应请求
     * @param handler 	处理请求的处理器对象
     * @return boolean  返回true表示继续执行下一个拦截器或处理器,返回false表示中断请求处理
     * @throws Exception 如果预处理过程中发生异常,则抛出异常
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取请求的URI并记录,以便于后续的日志审计或调试
        String requestURI = request.getRequestURI();
        log.info("请求的URI:{}",requestURI);

        // 获取请求头中的Authorization信息,用于验证用户身份
        String authorization = request.getHeader("authorization");
        log.info("请求的Authorization:{}",authorization);

        // 如果Authorization信息不为空,进一步验证用户身份
        if (authorization != null) {
            // 使用sa-token工具类,通过Authorization信息获取用户ID
            String userId = (String) StpUtil.getLoginIdByToken(authorization);
            log.info("用户ID:{}",userId);

            // 使用hutool工具类,验证用户ID是否为空,如果为空则抛出异常,表示用户未登录
            if (StrUtil.isBlank(userId)){
                throw new RuntimeException("用户未登录!");
            }
            // 将用户ID存入请求属性中,以便于后续的处理器可以使用
            request.setAttribute("userId",userId);
        } else {
            // 如果Authorization信息为空,记录日志并返回false,中断请求处理
            log.info("Token获取失败!");
            return false;
        }

        // 返回true,表示预处理完成,继续执行下一个拦截器或处理器
        return true;
    }
}

2、将拦截器添加到配置文件中

编辑config文件下的WebConfig类,代码如下:

 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
package com.example.demo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;


@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;
    /**
     * 配置拦截器
     *
     * 该方法用于向应用程序添加拦截器,以在请求处理之前或之后执行特定逻辑
     * 它特别指定了不需要拦截的路径,通常是登录和验证码相关的路径,以允许未登录的用户访问这些资源
     *
     * @param registry InterceptorRegistry的实例,用于注册拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 定义不需要拦截的路径列表,包括系统用户登录、普通用户登录和验证码相关路径
        List<String> excludePathList = List.of(
                "/system/user/login",
                "/user/login",
                "/captcha/**"
        );
        // 向registry中添加登录拦截器,应用于所有路径,但排除上述定义的路径
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**").excludePathPatterns(excludePathList);
    }
}

3、权限校验

1、创建拦截器

项目config文件下创建PermissionInterceptor类,代码如下:

 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
package com.example.demo.config;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Slf4j
@Component
public class PermissionInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 场景1:按角色校验:模拟从请求中获取用户角色
        String userRole = (String) request.getSession().getAttribute("userRole");

        // 模拟需要 ADMIN 角色才能访问的路径
        if (request.getRequestURI().startsWith("/admin/")) {
            if (!"ADMIN".equals(userRole)) {
                response.sendError(HttpServletResponse.SC_FORBIDDEN, "You don't have permission to access this resource.");
                return false;
            }
        }

        // 场景2:按接口权限校验:首次查询菜单权限时,将对应菜单关联的接口权限保存到redis中,后续直接从redis查询接口权限即可。


        


        return true;
    }
}

2、将拦截器添加到配置文件中

 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
package com.example.demo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private PermissionInterceptor permissionInterceptor;

    /**
     * 配置拦截器
     *
     * 该方法用于向应用程序添加拦截器,以在请求处理之前或之后执行特定逻辑
     *
     * @param registry InterceptorRegistry的实例,用于注册拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        // 可以添加多个拦截器registry.addInterceptor(拦截器).addPathPatterns("/**");

        // 向registry中添加权限拦截器,对所有路径进行拦截
        registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
    }
}