在后台,如果用户名登录错误,是有返回具体的错误异常信息的。但是在前台界面,却只看到了“Bad Credential”,而不是具体错误信息。
仔细跟踪代码,发现问题处在这里:
org.springframework.security.core.userdetails.UsernameNotFoundException: 用户名不正确
at cn.fredworks.security.service.authen.AuthenService.loadUserByUsername(AuthenService.java:66) ~[classes/:na]
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:104) ~[spring-security-core-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:144) ~[spring-security-core-5.0.6.RELEASE.jar:5.0.6.RELEASE]
这段代码中,抛出的异常,被 AbstractUserDetailsAuthenticationProvider 拦截了:
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.onlySupports",
"Only UsernamePasswordAuthenticationToken is supported"));
// Determine username
String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED"
: authentication.getName();
boolean cacheWasUsed = true;
UserDetails user = this.userCache.getUserFromCache(username);
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");
}
重点是其中的:
catch (UsernameNotFoundException notFound) {
logger.debug("User '" + username + "' not found");
if (hideUserNotFoundExceptions) {
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
else {
throw notFound;
}
}
如果 AbstractUserDetailsAuthenticationProvider 的属性 hideUserNotFoundExceptions 被设置为 true 了,就会隐藏原始的错误信息,而该属性的默认值就是 true。
我们在实际上,使用的是 AbstractUserDetailsAuthenticationProvider 的子类 DaoAuthenticationProvider。只要在spring-security配置时,设置其 hideUserNotFoundExceptions 为 false,就解决问题了。
我们可以这样,在javaconfig的配置类中,做如下处理:
@Configuration
public abstract class XxxModuleSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource(name = SecurityModuleBeanNames.SecurityModuleAuthenService)
private UserDetailsService userDetailService;
/**
* 构建自定义的DaoAuthenticationProvider
* @return
*/
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider bean = new DaoAuthenticationProvider();
bean.setHideUserNotFoundExceptions(false);
bean.setUserDetailsService(this.userDetailService);
bean.setPasswordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence rawPassword) {
try {
return CodecUtils.string2Md5String(rawPassword.toString());
} catch (Exception e) {
throw new BadCredentialsException("调用加密算法对密码进行加密时异常", e);
}
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if (StringUtils.isBlank(rawPassword)) {
throw new BadCredentialsException("没有提供密码");
} else if (StringUtils.isBlank(encodedPassword)) {
throw new BadCredentialsException("系统中密码密文是空白字符串");
} else {
return this.encode(rawPassword).equals(encodedPassword);
}
}
});
return bean;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(this.daoAuthenticationProvider());
}
处理到这里后,发现系统返回具体错误信息了,但仍然有问题,中文“用户名错误”是乱码。显然是因为spring-boot默认没有设置UTF-8编码所致。
在application.properties中设置如下:
# setting charset utf-8
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
server.tomcat.uri-encoding=UTF-8
服务重启后发现,乱码已经没有了
网友评论