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

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

该解决思路来自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);
                    }
                }
								// 如果在Realm中抛出异常, 
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在C++,try-catch语句用于捕获和处理异常。当程序的代码可能会引发异常时,我们可以使用try块来包裹这部分代码,并使用catch块来捕获并处理异常。 try块包含可能引发异常的代码,如果在try块的代码引发了异常,那么程序会立即跳转到与之匹配的catch块进行异常处理。 catch块用于捕获和处理异常。catch块可以指定捕获特定类型的异常,也可以使用通用的catch块来捕获所有类型的异常。在catch块,我们可以编写处理异常的代码逻辑,比如输出错误信息、进行日志记录、进行恢复操作等。 下面是一个简单的示例代码,演示了try-catch语句的使用: ```cpp try { // 可能引发异常的代码 throw MyException(); // 抛出自定义异常 } catch (const MyException& e) { // 处理自定义异常 std::cout << "Caught MyException: " << e.what() << std::endl; } catch (const std::exception& e) { // 处理其他类型的异常 std::cout << "Caught std::exception: " << e.what() << std::endl; } catch (...) { // 处理未知类型的异常 std::cout << "Caught unknown exception" << std::endl; } ``` 在上面的代码,try块抛出了一个自定义异常MyException。catch块按照顺序进行匹配,首先匹配到与MyException类型匹配的catch块,然后执行其的代码。如果没有匹配到特定类型的catch块,则会匹配到通用的catch块,执行其的代码。如果连通用的catch块也没有匹配到,则异常会继续向上层传递,直到找到匹配的catch块或者程序终止。 需要注意的是,catch块的参数可以是异常类型的引用或指针,通过该参数可以访问到抛出异常对象。在上面的示例,我们使用了const引用来捕获异常对象,并通过e.what()方法获取异常信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值