Spring Security修改默认的Bad Credentials提示 及其 原理(Spring Boot 2.0) 您所在的位置:网站首页 友邦isp修改登录密码错误 Spring Security修改默认的Bad Credentials提示 及其 原理(Spring Boot 2.0)

Spring Security修改默认的Bad Credentials提示 及其 原理(Spring Boot 2.0)

2024-07-16 03:30| 来源: 网络整理| 查看: 265

  Spring Security的各种提示内容来源于Spring的国际化资源文件类MessageSource,当我们想要修改默认提示时可能理所当然的会想到通过自己配置一个MessageSource的方式来实现,但是这种做法并不适用于Spring Security,原因如下,我们跟踪它的代码看看:

 

Spring Security的登录密码验证有一个默认的实现类叫做DaoAuthenticationProvider,如下:

 

它的登录验证方法是这个additionalAuthenticationChecks,如下:

 

可以看到当密码校验未通过时,它通过messages.getMessage()这个方法来获取提示信息,这个messages对象是一个MessageSourceAccessor,来源于它的一个抽象父类AbstractUserDetailsAuthenticationProvider,如下:

 

可以看到这个messages对象由SpringSecurityMessageSource.getAccessor()初始化 ,那么我们继续看看这个SpringSecurityMessageSource,如下:

 

到这步就很明了了, SpringSecurityMessageSource实际上继承自ResourceBundleMessageSource,它的getAccessor()是一个static方法。方法里new了一个自己,然后设置basename到了org.springframework.security.messages这个路径,这个路径实际上就是security-core包里面的一个路径。然后再new了一个新的MessageSourceAccessor。所以无论我们怎么配置我们自己的MessageSource都没有作用,因为Spring Security最后用到的这个MessageSourceAccessor是它自己new出来的,而不是Spring托管的。

 

那么,我们要怎样去修改这个Spring Security默认的提示呢?这里我的一个思路是:

① 我们自己去写一个AuthenticationProvider去继承这个Spring Security的登录校验父类DaoAuthenticationProvider

② 自己去配置一个MessageSource

③ 把我们自己配置的MessageSource赋值给父类DaoAuthenticationProvider的messages对象

④ 把自己的AuthenticationProvider设置给Spring Security

 

下面我们来看看具体步骤:

先写个简单的AuthenticationProvider(这里我的叫LoginAuthenticationProvider)如下:

@Component public class LoginAuthenticationProvider extends DaoAuthenticationProvider{ @Autowired private JdbcUserDetailsService jdbcUserDetailsService; @Autowired private PasswordEncoder passwordEncoder; @Autowired private void setJdbcUserDetailsService() { setUserDetailsService(jdbcUserDetailsService); } @PostConstruct public void initProvider() { ReloadableResourceBundleMessageSource localMessageSource = new ReloadableResourceBundleMessageSource(); localMessageSource.setBasenames("messages_zh_CN"); messages = new MessageSourceAccessor(localMessageSource); } @Override protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { if (authentication.getCredentials() == null) { logger.debug("Authentication failed: no credentials provided"); throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } String presentedPassword = authentication.getCredentials().toString(); if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { logger.debug("Authentication failed: password does not match stored value"); throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } } }

注意LoginAuthenticationProvider需要一个UserDetailsService,否则会启动失败,这里我用setter注入了一个我自己的UserDetailsService叫做JdbcUserDetailsService。记住一定要给自己的JdbcUserDetailsService打上@Component和@Order(0)注解,否则Spring在加载的时候有可能会先加载我们自己写的LoginAuthenticationProvider然后找不到JdbcUserDetailsService导致启动失败。

 

然后用@PostConstruct去写一个简单的初始化,在初始化的时候将一个我们自己配置的MessageSource(这里我使用的是ReloadableResourceBundleMessageSource)赋值给父类的messages对象。注意setBasenames()方法会自己查找src/main/resources下的.properties文件。这里我新建了一个文件叫messages_zh_CN.properties放在了src/main/resources下面,并且修改了里面的默认提示,如图:

最后在Spring Security的WebSecurityConfigurerAdapter里面配置我们自己的 LoginAuthenticationProvider即可,代码如下:

@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private LoginAuthenticationProvider loginAuthenticationProvider; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and().csrf().disable(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(loginAuthenticationProvider); super.configure(auth); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } }

 

本文参考:

https://www.jianshu.com/p/955e30866121

https://www.jianshu.com/p/46a4355ad0a3?from=groupmessage



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有