Spring 安全性 UserNotFoundException 未在使用 JSP 视图模板的 Spring 引导中显



我正在使用Spring Boot和JSP创建一个Web应用程序。我已经实现了 Spring 安全性,并且我正在覆盖loadUserByUsername()方法,当找不到用户时,我会抛出带有消息UsernameNotFoundException("User not found")。现在我想在我的登录页面中显示正确的消息,我该如何实现?

我的用户详细信息服务.java

package in.bushansirgur.security.service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import in.bushansirgur.security.entity.Role;
import in.bushansirgur.security.entity.User;
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
@Override
@Transactional
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException{
User user = userService.findUserByEmail(email);
if(user == null || user.getActive() == null){
throw new UsernameNotFoundException("User not found!");
}
List<GrantedAuthority> authorities = getUserAuthority(user.getRoles());
return buildUserForAuthentication(user, authorities);
}
...
}

登录控制器.java

@RequestMapping(value = {"/login", "/"})
public ModelAndView login(@RequestParam(name="error", required = false)String error, 
@RequestParam(name="logout", required = false)String logout, HttpServletRequest request
) throws UnknownHostException {     
// Port
String portNumber = environment.getProperty("server.port");
// Local address
String hostAddress = InetAddress.getLocalHost().getHostAddress();
String hostName = InetAddress.getLocalHost().getHostName();
System.out.println("Host address:"+hostAddress+" Host name:"+hostName+" Port number:"+portNumber);
// Remote address
InetAddress.getLoopbackAddress().getHostAddress();
InetAddress.getLoopbackAddress().getHostName();
ModelAndView mv = new ModelAndView("login");
if(error!=null) {
mv.addObject("message", "Invalid Username and Password!");
}
if(logout!=null) {
mv.addObject("logout", "User has successfully logged out!");
}
System.out.println("context path:"+request.getContextPath());
return mv;              
}

登录.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<c:set var="contextRoot" value="${pageContext.request.contextPath}" />
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<style>
.help-block {
color: #ff0000;
}
</style>
<body>
<h1>Login</h1>
<c:if test="${not empty message}">
<div class="row">
<div class="col-md-offset-3 col-md-6">
<div class="alert alert-danger">${message}</div>
</div>
</div>
</c:if>
<c:if test="${not empty logout}">
<div class="row">
<div class="col-md-offset-3 col-md-6">
<div class="alert alert-success">${logout}</div>
</div>
</div>
</c:if>
<form action="login" method="post" id="loginform">
<input type="text" name="email" placeholder="Enter email" /><br/>
<input type="password" name="password" placeholder="Enter password" /><br/>
<button type="submit">Login</button>
<%-- <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> --%>
</form>
<a href="${contextRoot}/registration">Register</a>
<script type="text/javascript" src="https://cdn.jsdelivr.net/jquery/latest/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-validation@1.17.0/dist/jquery.validate.js"></script>
<script>
$(function(){
const $loginForm = $("#loginform");
if($loginForm.length){
$loginForm.validate({
rules: {
email: {
required: true
},
password: {
required: true
}
},
messages: {
email: {
required: "Please enter email"
},
password: {
required: "Please enter password"
}
},
errorElement: 'em',
errorPlacement: function(error, element) {
error.addClass('help-block');
error.insertAfter(element);
}
})
}
})
</script>
</body>
</html>

网络安全配置.java

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Autowired
private MyUserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/registration").permitAll()
.antMatchers("/confirm-account").permitAll()
.antMatchers("/admin/**").hasAuthority("ADMIN")
.antMatchers("/user/**").hasAnyAuthority("ADMIN", "USER")
.anyRequest().authenticated().and().csrf().disable().formLogin()
.loginPage("/login")//.failureUrl("/login?error=true")
.defaultSuccessUrl("/dashboard")
.usernameParameter("email")
.passwordParameter("password")
.and().exceptionHandling().accessDeniedPage("/403");
}
...
}

JSP 中显示的错误消息是"用户名和密码无效"。那么,如果抛出UserNotFoundException,如何显示错误消息,例如"找不到用户"!

提前感谢!

默认情况下,如果未找到用户名或密码不正确,AbstractUserDetailsAuthenticationProvider会抛出 BadCredentialsException。 将此属性设置为 false 将导致为前者抛出UsernameNotFoundExceptions

请注意,这被认为不如为这两个异常抛出BadCredentialsException安全。为此,您必须实例化身份验证提供程序,如下所示:

@Bean
public AuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider impl = new DaoAuthenticationProvider();
impl.setUserDetailsService(yourUserDetailsService());
impl.setHideUserNotFoundExceptions(false) ;
return impl ;
}

警告:这样做不是良好的安全做法。

请参阅此处,setHideUserNotFoundExceptions和spring安全错误凭据区分无效的用户名或密码

最新更新