Spring Security6 教程

Spring Security6 403 响应状态处理

使用 Spring Security 时,经常会看见 403(无权限),默认情况下显示的效果如下图:

image.png

而在实际项目中可能是一个异步请求,因此显示上述效果对于用户就不是特别友好了。为了避免这种情况,Spring Security 支持用户自定义 403 权限受限错误。

自定义 AccessDeniedHandler

AccessDeniedHandler 接口的作用是对用户访问受保护资源时权限不足的情况进行处理。

接口定义如下:

package org.springframework.security.web.access;

import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;

/**
 * 由 {@link ExceptionTranslationFilter} 调用,处理访问被拒绝的情况
 * 当已认证用户尝试访问其权限不足的受保护资源时,会抛出 AccessDeniedException,
 * 此接口负责将该异常转换为适当的 HTTP 响应(如403状态码或重定向到错误页面)
 *
 * @see ExceptionTranslationFilter
 * @see AccessDeniedException
 */
public interface AccessDeniedHandler {

    /**
     * 处理访问被拒绝的请求
     * 
     * @param request 导致 AccessDeniedException 的 HTTP 请求
     * @param response 用于向客户端发送错误响应
     * @param accessDeniedException 访问被拒绝的异常对象
     * @throws IOException 发生 IO 异常时抛出
     * @throws ServletException 发生 Servlet 异常时抛出
     */
    void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException)
            throws IOException, ServletException;
}

创建 AccessDeniedHandler 实现类

@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, 
        HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
        httpServletResponse.setHeader("Content-Type","application/json;charset=utf-8");
        PrintWriter out = httpServletResponse.getWriter();
        out.write("{\"status\":\"error\",\"msg\":\"权限不足,请联系管理员!\"}");
        out.flush();
        out.close();
    }
}

注意,其中 mime 类型可以在 w3c 中进行查询 https://www.w3school.com.cn/media/media_mimeref.asp

修改 SecurityConfig 配置类

在配置类中添加异常处理器,设置访问受限后交给哪个对象进行处理。例如:

@Configuration
@EnableMethodSecurity(jsr250Enabled = true)
public class SecurityConfig {
    @Autowired
    private AccessDeniedHandler accessDeniedHandler;
    
    //...

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http, ObservationRegistry registry) throws Exception {
        System.out.println("securityFilterChain()");
        // csrfCustomizer.ignoringRequestMatchers(*) 表示所有请求地址都不使用 csrf
        http.csrf(csrfCustomizer -> csrfCustomizer.ignoringRequestMatchers("*"))
                // 配合注解,任何请求都需要授权才能访问
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/sys/**").hasRole("admin")
                        .anyRequest().authenticated())
                //...
                // 异常处理配置
                .exceptionHandling(customizer -> customizer.accessDeniedHandler(accessDeniedHandler))
                // 用于启用 HTTP 基本认证,withDefaults() 表示使用默认的 HTTP 基本认证配置。
                .httpBasic(withDefaults());

        return http.build();
    }

}

上述代码中,通过 HttpSecurity 类的 exceptionHandling() 方法配置注入。

运行项目

重启项目,通过浏览器访问 http://localhost:8080/sys/get 地址,效果如下:

image.png

 

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号