springboot项目中使用使用aop处理shiro自定义异常抛出

springboot项目中使用使用aop处理shiro自定义异常抛出

问题描述:

在 springboot 项目中做全局异常捕捉时,使用的是 spring 中的 @RestControllerAdvice@ExceptionHandler ,但是在 shiro 框架中 doGetAuthenticationInfo 抛出的异常并不能够被捕捉到。
案例:


	@Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = (String) authenticationToken.getPrincipal();
        throw new AuthenticationException("异常");	// 手动抛出异常
    }

全局捕获异常

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(AuthenticationException.class)
    public Result authenticationExceptionHandler(AuthenticationException e){
        return Result.fail(e.getMessage(), -1);
    }
}

结果:

{
    "timestamp": "2022-02-22T14:42:40.781+00:00",
    "status": 500,
    "error": "Internal Server Error",
    "trace": "org.apache.shiro.authc.AuthenticationException: 异常\r\n\tat com.library.backstage.redis.AccountRealm.doGetAuthenticationInfo(AccountRealm.java:44)\r\n\tat org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:571)\r\n\tat org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:180)\r\n\tat org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:273)\r\n\tat org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:198)\r\n\tat org.apache.shiro.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java:106)\r\n\tat org.apache.shiro.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:275)\r\n\tat org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:260)\r\n\tat com.library.backstage.redis.ShiroFilter.executeLogin(ShiroFilter.java:65)\r\n\tat org.apache.shiro.web.filter.authc.HttpAuthenticationFilter.onAccessDenied(HttpAuthenticationFilter.java:230)\r\n\tat org.apache.shiro.web.filter.AccessControlFilter.onAccessDenied(AccessControlFilter.java:133)\r\n\tat org.apache.shiro.web.filter.AccessControlFilter.onPreHandle(AccessControlFilter.java:162)\r\n\tat org.apache.shiro.web.filter.PathMatchingFilter.isFilterChainContinued(PathMatchingFilter.java:223)\r\n\tat org.apache.shiro.web.filter.PathMatchingFilter.preHandle(PathMatchingFilter.java:198)\r\n\tat com.library.backstage.redis.ShiroFilter.preHandle(ShiroFilter.java:85)\r\n\tat org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:131)\r\n\tat org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)\r\n\tat org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)\r\n\tat org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)\r\n\tat org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)\r\n\tat org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)\r\n\tat org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)\r\n\tat org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:450)\r\n\tat org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)\r\n\tat org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)\r\n\tat org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)\r\n\tat org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:387)\r\n\tat org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)\r\n\tat org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)\r\n\tat org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)\r\n\tat org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.lang.Thread.run(Thread.java:745)\r\n",
    "message": "异常",
    "path": "/test"
}

这不是我想要的结果,我想要的结果应该是异常的消息+状态码


原因分析:

查询了大量文档后,发现问题源自 shiro 的源码,spring 的 @RestControllerAdvice@ExceptionHandler 捕获的是 controller 层的异常,无法捕获拦截器中的异常,而 shiro 中的这个方法就是起到了拦截器的作用。


解决方案:

使用 spring 中的 aop 捕获拦截器中的异常
代码如下:

@Aspect
@Component
public class AllExceptionHandler {

    @Pointcut("execution(* com..AccountRealm.*(..))")
    public void pointcut(){}

    @AfterThrowing(pointcut = "pointcut()", throwing = "e")
    public void exceptionHandler(Throwable e){
        writeJson(Result.fail(e.getMessage(), -1));
    }

	// 写入结果集
    private void writeJson(Result result){
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        response.reset();
        response.setCharacterEncoding("UTF-8");
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
            writer.print(new JSONObject(result));	// 这里使用了hutool的json工具类
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.flush();
            writer.close();
        }
    }
}

结果:

{"data":"异常","errorCode":0,"stateCode":-1}
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
当然可以,以下是一个使用 ShiroSpring Boot 项目的示例: 首先,您需要在 pom.xml 文件添加以下依赖项: ```xml <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.4.2</version> </dependency> ``` 接下来,您需要在 application.properties 文件配置 Shiro: ```properties # Shiro 配置 shiro: # 登录 URL loginUrl: /login # 登录成功后跳转的 URL successUrl: /index # 未授权 URL unauthorizedUrl: /unauthorized # Shiro 过滤器链配置 filterChainDefinitions: /static/**=anon\n/login=anon\n/logout=logout\n/**=authc ``` 然后,您需要创建一个 Shiro 配置类: ```java @Configuration public class ShiroConfig { /** * 创建 Shiro 过滤器工厂 */ @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setSuccessUrl("/index"); shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized"); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/static/**", "anon"); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } /** * 创建 SecurityManager */ @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(realm()); return securityManager; } /** * 创建 Realm */ @Bean public Realm realm() { return new MyRealm(); } /** * 开启 Shiro 注解支持 */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } /** * 开启 Shiro AOP 支持 */ @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator(); creator.setProxyTargetClass(true); return creator; } } ``` 最后,您需要创建一个 Realm 类来处理身份验证和授权: ```java public class MyRealm extends AuthorizingRealm { /** * 处理授权 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.addRole("admin"); authorizationInfo.addStringPermission("user:list"); return authorizationInfo; } /** * 处理身份验证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); if (!"admin".equals(username)) { throw new UnknownAccountException("用户名或密码错误"); } if (!"123456".equals(password)) { throw new IncorrectCredentialsException("用户名或密码错误"); } return new SimpleAuthenticationInfo(username, password, getName()); } } ``` 这就是一个简单的使用 ShiroSpring Boot 项目的示例。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值