用户登录时的 Spring Boot 安全自定义消息 [英] Spring boot security custom messages while user login
问题描述
我正在尝试将 spring 安全性集成到我的 spring 启动应用程序中.一切正常,但如果帐户已过期或帐户被锁定,我该如何显示消息?另外,我不想显示基于 parm 的错误消息,例如 http://localhost:8080/login?error
这是我当前的代码:login.html
无效的用户名或密码.<h3>登录以继续</h3><form th:action="@{/login}" name="loginForm" method="POST"><div class="form-group"><label for="userNameInput">用户名</label><input type="text" class="form-control" id="userNameInput" name="username" placeholder="用户名"/>
<div class="form-group"><label for="passwordInput">密码</label><input type="password" class="form-control" id="passwordInput" name="password" placeholder="密码"/>
<button type="submit" class="btn btn-success">登录</button></表单>
WebSecurityConfig.java
@Configuration@启用网络安全公共类 WebSecurityConfig 扩展了 WebSecurityConfigurerAdapter {@自动连线private CustomUserDetailsService customUserDetailsService;@覆盖protected void configure(HttpSecurity http) 抛出异常 {http.authorizeRequests().antMatchers("/", "/css/**", "/js/**","/login/**").permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login").defaultSuccessUrl("/dashboard").and().logout().logoutSuccessUrl("/");}@自动连线public void configAuthBuilder(AuthenticationManagerBuilder auth) 抛出异常 {auth.userDetailsService(customUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());}}
CustomUserDetailsService.java
@Service公共类 CustomUserDetailsService 实现 UserDetailsService {@自动连线UserRepository userRepository;@覆盖@Transactional(readOnly = true)public UserDetails loadUserByUsername(String username) 抛出 UsernameNotFoundException {//从数据库查询用户用户用户 = userRepository.findByUsername(username);如果(用户==空){throw new UsernameNotFoundException(username);}今天的日期 = new Date();//检查帐户是否过期/暂停/删除布尔值 isAcconutExpired = false;布尔状态 = false;if (user.getExpireOn() != null && today.before(user.getExpireOn())) {isAcconutExpired = false;}if(user.getStatus() == 1){状态 = 真;}返回新的 org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),地位,!isAcconutExpired,真的,真的,getAuthorities(user));}私人列表getAuthorities(用户用户){列表权限 = 新的 ArrayList();authority.add(new SimpleGrantedAuthority("USER"));归还当局;}}
UserRepository.java
@Repository公共接口 UserRepository 扩展了 CrudRepository{用户 findByUsername(String username);}
这个消息有点旧,但我目前面临同样的问题.
因此,首先,您必须创建身份验证提供程序的自定义实例,以便将 HideUserNotFoundExceptions 传递给控制器:
public AuthenticationProvider daoAuthenticationProvider() {DaoAuthenticationProvider impl = new DaoAuthenticationProvider();impl.setUserDetailsService(customUserDetailsService);impl.setPasswordEncoder(new BCryptPasswordEncoder());impl.setHideUserNotFoundExceptions(false) ;返回实现;}
此外,您应该在 AuthenticationProviderBuilder 中添加此提供程序,而不是添加 customDetailService(添加 customDetailService 将添加其他提供程序):
@Autowiredpublic void configureGlobal(AuthenticationManagerBuilder auth) 抛出异常 {auth.authenticationProvider(daoAuthenticationProvider());}
有了这个,您现在可以捕获 UserNotFoundException 而不是基本的 BadCredentialsException .
因此,对于这两个异常,它仍然显示自定义错误消息.Badcredentials 异常由 SpringSecurity 直接抛出,错误消息基于 I18n 消息 AbstractUserDetailsAuthenticationProvider.badCredentials(参见 spring security 中的实现 rel="nofollow:here>
throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad Credentials"));
到期和帐户锁定相同.所以我建议你改变你的 CustomUserDetailsService.java 类来做同样的代码错误:
if (user == null) {throw new UsernameNotFoundException(SpringSecurityMessageSource.getAccessor().getMessage("AbstractUserDetailsAuthenticationProvider.UserUnknown",new Object[] {login},"User is not known"));}
在此之后,您可以在 message.properties 中添加这些行:
AbstractUserDetailsAuthenticationProvider.UserUnknown = {0} 未找到.AbstractUserDetailsAuthenticationProvider.badCredentials = 密码错误AbstractUserDetailsAuthenticationProvider.credentialsExpired = 用户凭据已过期AbstractUserDetailsAuthenticationProvider.disabled = 用户被禁用AbstractUserDetailsAuthenticationProvider.expired = 用户帐户已过期AbstractUserDetailsAuthenticationProvider.locked = 用户帐户被锁定
并在 login.html 中显示错误信息:
<label th:if="${param.error}" th:text="${session['SPRING_SECURITY_LAST_EXCEPTION'].message}" class="text-center redText">Mot de passe inconnu</label>
I am trying to integrate spring security in my spring boot application.All working ok but how do I display a message if the account is expired or account is locked? Also, I do not want to display error message based on parm like http://localhost:8080/login?error
Here is my current code: login.html
<div th:if="${param.error}" class="alert alert-danger">
Invalid username or password.
</div>
<h3>Sign in to continue</h3>
<form th:action="@{/login}" name="loginForm" method="POST">
<div class="form-group">
<label for="userNameInput">Username</label>
<input type="text" class="form-control" id="userNameInput" name="username" placeholder="Username" />
</div>
<div class="form-group">
<label for="passwordInput">Password</label>
<input type="password" class="form-control" id="passwordInput" name="password" placeholder="Password" />
</div>
<button type="submit" class="btn btn-success">Login</button>
</form>
WebSecurityConfig.java
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/css/**", "/js/**","/login/**").permitAll()
.anyRequest().authenticated()
.and().formLogin().loginPage("/login").defaultSuccessUrl("/dashboard")
.and().logout().logoutSuccessUrl("/");
}
@Autowired
public void configAuthBuilder(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
}
CustomUserDetailsService.java
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
UserRepository userRepository;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//query for user from DB
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException(username);
}
Date today = new Date();
//do check if account expired / suspended / deleted
Boolean isAcconutExpired = false;
Boolean status = false;
if (user.getExpireOn() != null && today.before(user.getExpireOn())) {
isAcconutExpired = false;
}
if(user.getStatus() == 1){
status = true;
}
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(),
status,
!isAcconutExpired,
true,
true,
getAuthorities(user));
}
private List<GrantedAuthority> getAuthorities(User user) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("USER"));
return authorities;
}
}
UserRepository.java
@Repository
public interface UserRepository extends CrudRepository<User, Long> {
User findByUsername(String username);
}
This message is a bit old, but I'm currently facing the same problem.
So, firstly, you have to create a custom instance of Authentication Provider to let HideUserNotFoundExceptions be passed to the controler:
public AuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider impl = new DaoAuthenticationProvider();
impl.setUserDetailsService(customUserDetailsService);
impl.setPasswordEncoder(new BCryptPasswordEncoder());
impl.setHideUserNotFoundExceptions(false) ;
return impl ;
}
Moreover, you should add this provider in the AuthenticationProviderBuilder, instead of adding customDetailService (adding customDetailService will add an other provider) :
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
With this, you can now catch UserNotFoundException instead of basic BadCredentialsException .
So, it remains to display custom error message for these two exceptions. The Badcredentials exception is throw directly by SpringSecurity with an error message based on I18n message AbstractUserDetailsAuthenticationProvider.badCredentials (see the implementation in spring security here ):
throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
Same for expiration and account locked. So I suggest you to change your CustomUserDetailsService.java class to do the same with a similar code error :
if (user == null) {
throw new UsernameNotFoundException(SpringSecurityMessageSource.getAccessor().getMessage("AbstractUserDetailsAuthenticationProvider.UserUnknown",new Object[] {login},"User is not known"));
}
After this, you can add these lines in your message.properties :
AbstractUserDetailsAuthenticationProvider.UserUnknown = {0} was not found.
AbstractUserDetailsAuthenticationProvider.badCredentials = Password is bad
AbstractUserDetailsAuthenticationProvider.credentialsExpired = User credentials have expired
AbstractUserDetailsAuthenticationProvider.disabled = User is disabled
AbstractUserDetailsAuthenticationProvider.expired = User account has expired
AbstractUserDetailsAuthenticationProvider.locked = User account is locked
And display error message in login.html :
<div class="dialog-row">
<label th:if="${param.error}" th:text="${session['SPRING_SECURITY_LAST_EXCEPTION'].message}" class="text-center redText">Mot de passe inconnu</label>
</div>
这篇关于用户登录时的 Spring Boot 安全自定义消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!