关于Spring Security自定义认证时,异常处理的问题
问题描述:
我们在利用springSecurity进行认证时,如果没有配置认证失败处理器,想要在自己实现UserDetailsService中抛出异常来进行提示用户用户名错误时,再利用全局异常处理器是无法捕获到自己抛出的异常。
自己实现的UserDetailsService
全局异常处理类
Spring Security配置没有配置认证失败处理器,希望用全局异常处理来提供给前端失败的信息。
测试结果
此时,给我们返回的提示信息是系统异常,这是因为在全局异常处理时,我们处理了Exception,也就是除了我们自定义的异常之外,其余的异常统称为系统异常。
分析结果产生原因
根据控制台的输出结果,我们看到,有两个异常,一个是InternalAuthenticationServiceException,另一个是我们自定义的异常类BizException。
在此我们可以分析出原因,为什么没有给我返回自定义异常的处理,是因为InternalAuthenticationServiceException先被抛出了,因此全局异常处理类处理了该异常,并将其作为系统异常。
此时又有疑问了,明明是自定义异常先抛出的,为什么会捕获不到呢?我们来看一下源码:ProviderManager类中的authenticate方法。
在红框中我们发现,此部分将我们抛出的异常捕获了,然后并没有抛出,而是抛出了一个新的异常,也就是InternalAuthenticationServiceException。所以我们才会收到该异常。
解决办法
解决办法有很多,有的麻烦,有的简单。我们可以有以下的解决办法:
- 重写ProviderManager,然后将捕获异常改为抛出自定义异常,此方法就是很麻烦,需要重写代码。
- 在全局异常处理中,处理该异常类,也可以做到自定义提示。但是此方法就仅限于用户不存在的情况。
- 可以直接自定义一个认证失败处理类,然后此类就可以捕获到有异常的情况,然后把提示信息直接输出给前端就可以了。但是此方法也有一些的问题,下一部分再说。
第三种方法的实现:
重写方法,然后将异常信息给到前端即可。
然后将其配置到配置类中。
测试结果
成功提示!