JavaEE中Pac4j异常处理问题:自定义权限异常无法触发指定错误页
解决pac4j包装异常导致web.xml错误页不生效的问题
问题根源
pac4j的org.pac4j.core.engine.AbstractExceptionAwareLogic#handleException方法会将捕获到的ServletException二次包装为RuntimeException,导致web.xml中基于自定义PermissionDeniedException的错误页映射无法识别原异常类型,进而无法触发对应错误页。
无需自定义SecurityFilter的解决方案
方案1:自定义SecurityLogic覆盖异常处理逻辑
继承pac4j默认的DefaultSecurityLogic,重写handleException方法,针对ServletException直接抛出而非包装:
public class CustomSecurityLogic extends DefaultSecurityLogic { @Override protected RuntimeException handleException(Exception e, WebContext context, SecurityConfig securityConfig) { // 对ServletException直接抛出,保留原异常类型 if (e instanceof ServletException) { throw (ServletException) e; } // 其他异常沿用原有处理逻辑 return super.handleException(e, context, securityConfig); } }
在web.xml的SecurityFilter配置中指定自定义逻辑类:
<filter> <filter-name>securityFilter</filter-name> <filter-class>org.pac4j.core.engine.SecurityFilter</filter-class> <init-param> <param-name>securityLogic</param-name> <param-value>com.your.package.CustomSecurityLogic</param-value> </init-param> <!-- 其他pac4j配置参数 --> </filter>
方案2:注册自定义ExceptionHandler
实现pac4j的ExceptionHandler接口,在异常被包装前拦截并处理目标异常:
public class CustomExceptionHandler implements ExceptionHandler { @Override public void handleException(Exception e, WebContext context) { // 识别嵌套PermissionDeniedException的ServletException,直接抛出 if (e instanceof ServletException se) { if (se.getRootCause() instanceof PermissionDeniedException) { throw se; } } // 非目标异常交给默认处理器处理 DefaultExceptionHandler.INSTANCE.handleException(e, context); } }
在pac4j的Config初始化时注册该处理器:
Config pac4jConfig = new Config(yourClient); pac4jConfig.setExceptionHandler(new CustomExceptionHandler());
方案3:调整web.xml错误页映射(快速适配)
修改web.xml,将RuntimeException映射到目标错误页,然后在错误页中判断原异常类型:
<error-page> <exception-type>java.lang.RuntimeException</exception-type> <location>/access.xhtml</location> </error-page>
在/access.xhtml中通过EL表达式获取根异常并判断:
<ui:fragment rendered="#{requestScope['jakarta.servlet.error.exception'].rootCause instanceof com.your.package.PermissionDeniedException}"> <!-- 权限不足提示内容 --> </ui:fragment> <ui:fragment rendered="#{not (requestScope['jakarta.servlet.error.exception'].rootCause instanceof com.your.package.PermissionDeniedException)}"> <!-- 其他运行时异常提示内容 --> </ui:fragment>
内容的提问来源于stack exchange,提问作者user23367667
相关产品推荐
相关产品推荐

