Shiro getAuthenticationInfo()中抛出异常, 全局异常处理却收不到自己抛出的异常

当Shiro在getAuthenticationInfo()中抛出异常时,全局异常处理无法捕获。原因是默认的AuthenticationStrategy导致。解决方案是实现自定义AuthenticationStrategy并正确配置。尝试通过Spring Boot YAML配置、shiro.ini配置、创建Bean方式失败。最终,通过获取SecurityManager的Authenticator并设置自定义Strategy成功解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该解决思路来自StackOverflow: Apache Shiro: Exception-Handling with Multiple Realms

首先下结论: 这是因为使用了默认的AuthenticationStrategy所致, 只需要为自己的shiro实现自定义的AuthenticationStrategy, 并将其正确配置即可.

public class MyAtLeastOneSuccessfulStrategy extends AtLeastOneSuccessfulStrategy {
   
    @Override
    public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
   
        if (t != null && t instanceof AuthenticationException){
   
            throw (AuthenticationException) t;
        }
        return super.afterAttempt(realm, token, singleRealmInfo, aggregateInfo, t);
    }
}

配置AuthenticationStrategy的方法如下:

MyAtLeastOneSuccessfulStrategy strategy = new MyAtLeastOneSuccessfulStrategy();
((ModularRealmAuthenticator)(securityManager.getAuthenticator()))
														.setAuthenticationStrategy(strategy);

如果希望知道为何收到的是AuthenticationException, 以及为何要按照上面这么配置. 请看源码分析(我的经历):

为何总是收不到自己throw的异常

doGetAuthenticationInfo方法中

if (user == null)
            throw new UnknownAccountException("账户不存在!");

在调用一堆构造函数后, 进入ModularRealmAuthenticator的doMultiRealmAuthentication方法

protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, 
                        AuthenticationToken token) {
   
				
				// 获取验证策略
        AuthenticationStrategy strategy = getAuthenticationStrategy();

        AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token);
				// 日志
        if (log.isTraceEnabled()) {
   
            log.trace("Iterating through {} realms for PAM authentication", realms.size());
        }
				
				// 循环遍历realm
        for (Realm realm : realms) {
   
						// 
            try {
   
                aggregate = strategy.beforeAttempt(realm, token, aggregate);
            } catch (ShortCircuitIterationException shortCircuitSignal) {
   
                // Break from continuing with subsequnet realms on receiving 
                // short circuit signal from strategy
                break;
            }

            if (realm.supports(token)) {
   

                log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm);

                AuthenticationInfo info = null;
                Throwable t = null;
                try {
   
										**// 这里调用了自定义Realm的getAuthenticationInfo方法**
                    **info = realm.getAuthenticationInfo(token);**
                } catch (Throwable throwable) {
   
										**// 这里采用catch将Realm中抛出的异常直接捕获, 
										// 并且在后续的处理中并没有将该异常重新抛出**
                    t = throwable;
                    if (log.isDebugEnabled()) {
   
                        String msg = "Realm [" + realm + "] threw an exception during a multi-realm authentication attempt:";
                        log.debug(msg, t);
                    }
                
### 拦截器中重写方法时抛出异常的原因 在Spring框架下,拦截器作为AOP(面向切面编程)的一种实现方式,在特定阶段可以对请求进行预处理或后处理。当在拦截器内重写了某些方法并选择抛出异常时,这通常是为了满足业务逻辑需求以及确保系统的健壮性和安全性。 #### 异常抛出的目的 如果在`preHandle()`方法中检测到不符合预期的情况,则可以通过抛出异常来阻止后续操作继续执行[^1]。例如: - **验证失败**:假设存在权限校验的需求,此时可以在该方法里检查当前用户的访问资格。一旦发现用户不具备相应权限就立即终止流程并向前端返回错误提示信息。 - **参数合法性检验**:对于传入的数据同样适用此原则。任何非法输入都应尽早被捕获,并通过适当的方式通知调用方以便及时修正问题所在。 ```java @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 假设这里进行了某种条件判断 if (!isValidCondition()) { throw new CustomException("Invalid condition detected"); } return true; } ``` 这种做法不仅有助于提高程序稳定性,还能简化代码结构——因为不再需要层层传递状态码或其他形式的结果标记给上层函数去决定下一步动作。 #### 抛出异常的影响范围 需要注意的是,由于拦截器位于DispatcherServlet之后、目标控制器之前的位置工作[^2],因此所引发的未捕获异常会直接交还给全局异常处理器负责处置。这意味着开发人员应当谨慎设计自己的异常类及其传播路径,以免造成不必要的混乱或者安全风险。 此外,考虑到整个Web应用可能依赖于统一的异常管理体系,建议遵循既定的最佳实践模式来进行此类编码活动。比如创建专门针对API层面定义的一系列受检/非受检异常类型,从而更好地服务于前后端交互过程中的各种场景。 #### 实际案例分析 有时会在配置过程中遇到诸如Shiro+jwt组合使用时因为空指针而导致的异常情况[^4]。这类问题是比较典型的配置失误所致,即未能正确初始化必要的组件对象便尝试对其进行访问。为了避免这种情况的发生,务必仔细审查项目设置文件内的各项属性值是否合理有效。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值