spring security oauth2中UsernameNotFoundException无法在认证失败后被捕获的问题

1.问题描述:

在认证失败后UsernameNotFoundException异常会被默认转换成BadCredentialsException异常,导致不能捕获到UsernameNotFoundException, 一般来说UsernameNotFoundException是用户名错误导致的登录失败,BadCredentialsException是用户名或者密码错误导致的登录失败。如果我们能捕获到UsernameNotFoundException就能很好的区分登录失败是哪种具体的原因,以便在某些时候做一些对应的逻辑处理。

2.解决方案:

在AbstractUserDetailsAuthenticationProvider中有这么一段代码:

public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		//...
			
		if (user == null) {
			cacheWasUsed = false;

			try {
				user = retrieveUser(username,
						(UsernamePasswordAuthenticationToken) authentication);
			}
			catch (UsernameNotFoundException notFound) {
				logger.debug("User '" + username + "' not found");

				if (hideUserNotFoundExceptions) {
					throw new BadCredentialsException(messages.getMessage(
							"AbstractUserDetailsAuthenticationProvider.badCredentials",
							"Bad credentials"));
				} else {
					throw notFound;
				}
			}

			Assert.notNull(user,
					"retrieveUser returned null - a violation of the interface contract");
		}

		// ...
	}

可以看到hideUserNotFoundExceptions为true的时候UsernameNotFoundException就会被转换成BadCredentialsException异常,而hideUserNotFoundExceptions的默认值是true,所以我们只需要修改hideUserNotFoundExceptions为false即可解决问题。以下是具体方案:

在WebSecurityConfigurerAdapter的实现类配置中添加如下配置:

@Primary
@Order(90)
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
	@Autowired
	private UserDetailsService userDetailsService;
	//...
	
	@Override
	public void configure(AuthenticationManagerBuilder auth) {
		auth.authenticationProvider(authenticationProvider());
	}
	
	//可以配置成一个Bean
	private DaoAuthenticationProvider authenticationProvider() {
		DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
		//设置hideUserNotFoundExceptions为false
		provider.setHideUserNotFoundExceptions(false);
		//userDetailsService是你自己的userDetailsService实现类,
		//UsernameNotFoundException就是其中抛出来的
		provider.setUserDetailsService(userDetailsService);
		provider.setPasswordEncoder(passwordEncoder());
		return provider;
	}
	
    //...
}

认证失败事件处理:

import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

@Component
public class AuthenticationFailureEvenHandler implements ApplicationListener<AbstractAuthenticationFailureEvent> {
	@Override
	public void onApplicationEvent(AbstractAuthenticationFailureEvent event) {
		AuthenticationException authenticationException = event.getException();
		Authentication authentication = (Authentication) event.getSource();
		handle(authenticationException, authentication);
	}

	public void handle(AuthenticationException exc, Authentication auth){
		//获取一些参数
		String username = (String)auth.getPrincipal();
		Map<String,Object> params= (Map<String,Object>)auth.getDetails();
		
		if (exc instanceof BadCredentialsException){
			//密码错误导致的登录失败
			//TODO...
		}else if(exc instanceof UsernameNotFoundException){
			//用户名不存在导致的登录失败
			//TODO...
		}
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值