Java Spring MVC、Spring安全性:无法加载登录模板
当访问任何路由时,我会被重定向到我的登录页面,包括访问我的登录页面,这是预期的。现在的问题是登录页面甚至没有加载。我已经配置了控制器方法、hander、模板配置和安全配置,这些都是实现此功能所必需的,但我得到的只是以下错误: UserController.javaJava Spring MVC、Spring安全性:无法加载登录模板,java,spring,spring-mvc,spring-boot,spring-security,Java,Spring,Spring Mvc,Spring Boot,Spring Security,当访问任何路由时,我会被重定向到我的登录页面,包括访问我的登录页面,这是预期的。现在的问题是登录页面甚至没有加载。我已经配置了控制器方法、hander、模板配置和安全配置,这些都是实现此功能所必需的,但我得到的只是以下错误: UserController.java @Controller public class UserController { @Autowired private UserService userService; @GetMapping("/si
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/signup")
public String signup(Model model) {
model.addAttribute("user", new User());
return "signup";
}
@PostMapping("/users")
public String createUser(User user) {
// only create user if it does not exist
if (userService.findByUsername(user.getUsername()) == null) {
user.setRoles(new String[] {"ROLE_USER"});
userService.save(user);
return "redirect:/login";
}
else {
return "redirect:/signup";
}
}
@GetMapping("/login")
public String login(Model model) {
model.addAttribute("user", new User());
return "login";
}
@GetMapping("/profile")
public String currentUserProfile(Model model) {
User currentUser = (User) model.asMap().get("currentUser");
model.addAttribute("user", currentUser);
model.addAttribute("authorized", true);
return "profile";
}
@GetMapping("/users/{id}")
public String userProfile(@PathVariable Long id, Model model) {
User queriedUser = userService.findOne(id);
model.addAttribute("user", queriedUser);
User currentUser = (User) model.asMap().get("currentUser");
if (currentUser != null && currentUser.isAdmin()) {
model.addAttribute("authorized", true);
}
return "profile";
}
}
@ControllerAdvice(basePackages = "com.valencra.recipes.web.controller")
public class UserHandler {
public static final String USERNAME_NOT_FOUND_ERR_MSG = "Unable to find username";
public static final String ACCESS_DENIED_ERR_MSG = "Login to use the app";
@Autowired
private UserService userService;
@ModelAttribute("authenticatedUser")
public User addAuthenticatedUser() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
String username = authentication.getName();
User user = userService.findByUsername(username);
if (user != null) {
return user;
}
else {
throw new UsernameNotFoundException(USERNAME_NOT_FOUND_ERR_MSG);
}
}
else {
throw new AccessDeniedException(ACCESS_DENIED_ERR_MSG);
}
}
@ExceptionHandler(AccessDeniedException.class)
public String redirectIfUserNotAuthenticated(RedirectAttributes redirectAttributes) {
redirectAttributes.addAttribute("errorMessage", ACCESS_DENIED_ERR_MSG);
return "redirect:/login";
}
@ExceptionHandler(UsernameNotFoundException.class)
public String redirectIfUserNotFound(RedirectAttributes redirectAttributes) {
redirectAttributes.addAttribute("errorMessage", USERNAME_NOT_FOUND_ERR_MSG);
return "redirect:/login";
}
}
@Configuration
public class TemplateConfig {
@Bean
public SpringResourceTemplateResolver templateResolver() {
final SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("LEGACYHTML5");
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
final SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.addTemplateResolver(templateResolver());
springTemplateEngine.addDialect(new SpringSecurityDialect());
return springTemplateEngine;
}
@Bean
public ThymeleafViewResolver viewResolver() {
final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RecipesAppUserDetailsService recipesAppUserDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(recipesAppUserDetailsService)
.passwordEncoder(User.PASSWORD_ENCODER);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/signup").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.successHandler(loginSuccessHandler())
.failureHandler(loginFailureHandler())
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/login")
.and()
.csrf().disable();
http.headers().frameOptions().disable();
}
public AuthenticationSuccessHandler loginSuccessHandler() {
return (request, response, authentication) -> response.sendRedirect("/");
}
public AuthenticationFailureHandler loginFailureHandler() {
return (request, response, exception) ->
response.sendRedirect("/login");
}
@Bean
public EvaluationContextExtension securityExtension() {
return new EvaluationContextExtensionSupport() {
@Override
public String getExtensionId() {
return "security";
}
@Override
public Object getRootObject() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return new SecurityExpressionRoot(authentication) {};
}
};
}
}
UserHandler.java
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/signup")
public String signup(Model model) {
model.addAttribute("user", new User());
return "signup";
}
@PostMapping("/users")
public String createUser(User user) {
// only create user if it does not exist
if (userService.findByUsername(user.getUsername()) == null) {
user.setRoles(new String[] {"ROLE_USER"});
userService.save(user);
return "redirect:/login";
}
else {
return "redirect:/signup";
}
}
@GetMapping("/login")
public String login(Model model) {
model.addAttribute("user", new User());
return "login";
}
@GetMapping("/profile")
public String currentUserProfile(Model model) {
User currentUser = (User) model.asMap().get("currentUser");
model.addAttribute("user", currentUser);
model.addAttribute("authorized", true);
return "profile";
}
@GetMapping("/users/{id}")
public String userProfile(@PathVariable Long id, Model model) {
User queriedUser = userService.findOne(id);
model.addAttribute("user", queriedUser);
User currentUser = (User) model.asMap().get("currentUser");
if (currentUser != null && currentUser.isAdmin()) {
model.addAttribute("authorized", true);
}
return "profile";
}
}
@ControllerAdvice(basePackages = "com.valencra.recipes.web.controller")
public class UserHandler {
public static final String USERNAME_NOT_FOUND_ERR_MSG = "Unable to find username";
public static final String ACCESS_DENIED_ERR_MSG = "Login to use the app";
@Autowired
private UserService userService;
@ModelAttribute("authenticatedUser")
public User addAuthenticatedUser() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
String username = authentication.getName();
User user = userService.findByUsername(username);
if (user != null) {
return user;
}
else {
throw new UsernameNotFoundException(USERNAME_NOT_FOUND_ERR_MSG);
}
}
else {
throw new AccessDeniedException(ACCESS_DENIED_ERR_MSG);
}
}
@ExceptionHandler(AccessDeniedException.class)
public String redirectIfUserNotAuthenticated(RedirectAttributes redirectAttributes) {
redirectAttributes.addAttribute("errorMessage", ACCESS_DENIED_ERR_MSG);
return "redirect:/login";
}
@ExceptionHandler(UsernameNotFoundException.class)
public String redirectIfUserNotFound(RedirectAttributes redirectAttributes) {
redirectAttributes.addAttribute("errorMessage", USERNAME_NOT_FOUND_ERR_MSG);
return "redirect:/login";
}
}
@Configuration
public class TemplateConfig {
@Bean
public SpringResourceTemplateResolver templateResolver() {
final SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("LEGACYHTML5");
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
final SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.addTemplateResolver(templateResolver());
springTemplateEngine.addDialect(new SpringSecurityDialect());
return springTemplateEngine;
}
@Bean
public ThymeleafViewResolver viewResolver() {
final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RecipesAppUserDetailsService recipesAppUserDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(recipesAppUserDetailsService)
.passwordEncoder(User.PASSWORD_ENCODER);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/signup").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.successHandler(loginSuccessHandler())
.failureHandler(loginFailureHandler())
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/login")
.and()
.csrf().disable();
http.headers().frameOptions().disable();
}
public AuthenticationSuccessHandler loginSuccessHandler() {
return (request, response, authentication) -> response.sendRedirect("/");
}
public AuthenticationFailureHandler loginFailureHandler() {
return (request, response, exception) ->
response.sendRedirect("/login");
}
@Bean
public EvaluationContextExtension securityExtension() {
return new EvaluationContextExtensionSupport() {
@Override
public String getExtensionId() {
return "security";
}
@Override
public Object getRootObject() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return new SecurityExpressionRoot(authentication) {};
}
};
}
}
TemplateConfig.java
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/signup")
public String signup(Model model) {
model.addAttribute("user", new User());
return "signup";
}
@PostMapping("/users")
public String createUser(User user) {
// only create user if it does not exist
if (userService.findByUsername(user.getUsername()) == null) {
user.setRoles(new String[] {"ROLE_USER"});
userService.save(user);
return "redirect:/login";
}
else {
return "redirect:/signup";
}
}
@GetMapping("/login")
public String login(Model model) {
model.addAttribute("user", new User());
return "login";
}
@GetMapping("/profile")
public String currentUserProfile(Model model) {
User currentUser = (User) model.asMap().get("currentUser");
model.addAttribute("user", currentUser);
model.addAttribute("authorized", true);
return "profile";
}
@GetMapping("/users/{id}")
public String userProfile(@PathVariable Long id, Model model) {
User queriedUser = userService.findOne(id);
model.addAttribute("user", queriedUser);
User currentUser = (User) model.asMap().get("currentUser");
if (currentUser != null && currentUser.isAdmin()) {
model.addAttribute("authorized", true);
}
return "profile";
}
}
@ControllerAdvice(basePackages = "com.valencra.recipes.web.controller")
public class UserHandler {
public static final String USERNAME_NOT_FOUND_ERR_MSG = "Unable to find username";
public static final String ACCESS_DENIED_ERR_MSG = "Login to use the app";
@Autowired
private UserService userService;
@ModelAttribute("authenticatedUser")
public User addAuthenticatedUser() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
String username = authentication.getName();
User user = userService.findByUsername(username);
if (user != null) {
return user;
}
else {
throw new UsernameNotFoundException(USERNAME_NOT_FOUND_ERR_MSG);
}
}
else {
throw new AccessDeniedException(ACCESS_DENIED_ERR_MSG);
}
}
@ExceptionHandler(AccessDeniedException.class)
public String redirectIfUserNotAuthenticated(RedirectAttributes redirectAttributes) {
redirectAttributes.addAttribute("errorMessage", ACCESS_DENIED_ERR_MSG);
return "redirect:/login";
}
@ExceptionHandler(UsernameNotFoundException.class)
public String redirectIfUserNotFound(RedirectAttributes redirectAttributes) {
redirectAttributes.addAttribute("errorMessage", USERNAME_NOT_FOUND_ERR_MSG);
return "redirect:/login";
}
}
@Configuration
public class TemplateConfig {
@Bean
public SpringResourceTemplateResolver templateResolver() {
final SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("LEGACYHTML5");
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
final SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.addTemplateResolver(templateResolver());
springTemplateEngine.addDialect(new SpringSecurityDialect());
return springTemplateEngine;
}
@Bean
public ThymeleafViewResolver viewResolver() {
final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RecipesAppUserDetailsService recipesAppUserDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(recipesAppUserDetailsService)
.passwordEncoder(User.PASSWORD_ENCODER);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/signup").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.successHandler(loginSuccessHandler())
.failureHandler(loginFailureHandler())
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/login")
.and()
.csrf().disable();
http.headers().frameOptions().disable();
}
public AuthenticationSuccessHandler loginSuccessHandler() {
return (request, response, authentication) -> response.sendRedirect("/");
}
public AuthenticationFailureHandler loginFailureHandler() {
return (request, response, exception) ->
response.sendRedirect("/login");
}
@Bean
public EvaluationContextExtension securityExtension() {
return new EvaluationContextExtensionSupport() {
@Override
public String getExtensionId() {
return "security";
}
@Override
public Object getRootObject() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return new SecurityExpressionRoot(authentication) {};
}
};
}
}
SecurityConfig.java
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/signup")
public String signup(Model model) {
model.addAttribute("user", new User());
return "signup";
}
@PostMapping("/users")
public String createUser(User user) {
// only create user if it does not exist
if (userService.findByUsername(user.getUsername()) == null) {
user.setRoles(new String[] {"ROLE_USER"});
userService.save(user);
return "redirect:/login";
}
else {
return "redirect:/signup";
}
}
@GetMapping("/login")
public String login(Model model) {
model.addAttribute("user", new User());
return "login";
}
@GetMapping("/profile")
public String currentUserProfile(Model model) {
User currentUser = (User) model.asMap().get("currentUser");
model.addAttribute("user", currentUser);
model.addAttribute("authorized", true);
return "profile";
}
@GetMapping("/users/{id}")
public String userProfile(@PathVariable Long id, Model model) {
User queriedUser = userService.findOne(id);
model.addAttribute("user", queriedUser);
User currentUser = (User) model.asMap().get("currentUser");
if (currentUser != null && currentUser.isAdmin()) {
model.addAttribute("authorized", true);
}
return "profile";
}
}
@ControllerAdvice(basePackages = "com.valencra.recipes.web.controller")
public class UserHandler {
public static final String USERNAME_NOT_FOUND_ERR_MSG = "Unable to find username";
public static final String ACCESS_DENIED_ERR_MSG = "Login to use the app";
@Autowired
private UserService userService;
@ModelAttribute("authenticatedUser")
public User addAuthenticatedUser() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
String username = authentication.getName();
User user = userService.findByUsername(username);
if (user != null) {
return user;
}
else {
throw new UsernameNotFoundException(USERNAME_NOT_FOUND_ERR_MSG);
}
}
else {
throw new AccessDeniedException(ACCESS_DENIED_ERR_MSG);
}
}
@ExceptionHandler(AccessDeniedException.class)
public String redirectIfUserNotAuthenticated(RedirectAttributes redirectAttributes) {
redirectAttributes.addAttribute("errorMessage", ACCESS_DENIED_ERR_MSG);
return "redirect:/login";
}
@ExceptionHandler(UsernameNotFoundException.class)
public String redirectIfUserNotFound(RedirectAttributes redirectAttributes) {
redirectAttributes.addAttribute("errorMessage", USERNAME_NOT_FOUND_ERR_MSG);
return "redirect:/login";
}
}
@Configuration
public class TemplateConfig {
@Bean
public SpringResourceTemplateResolver templateResolver() {
final SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("LEGACYHTML5");
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
final SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.addTemplateResolver(templateResolver());
springTemplateEngine.addDialect(new SpringSecurityDialect());
return springTemplateEngine;
}
@Bean
public ThymeleafViewResolver viewResolver() {
final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RecipesAppUserDetailsService recipesAppUserDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(recipesAppUserDetailsService)
.passwordEncoder(User.PASSWORD_ENCODER);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/signup").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.successHandler(loginSuccessHandler())
.failureHandler(loginFailureHandler())
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/login")
.and()
.csrf().disable();
http.headers().frameOptions().disable();
}
public AuthenticationSuccessHandler loginSuccessHandler() {
return (request, response, authentication) -> response.sendRedirect("/");
}
public AuthenticationFailureHandler loginFailureHandler() {
return (request, response, exception) ->
response.sendRedirect("/login");
}
@Bean
public EvaluationContextExtension securityExtension() {
return new EvaluationContextExtensionSupport() {
@Override
public String getExtensionId() {
return "security";
}
@Override
public Object getRootObject() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return new SecurityExpressionRoot(authentication) {};
}
};
}
}
应用程序属性
# Package where our entities (models) are located
recipes.entity.package = com.valencra.recipes.model
# Details for our datasource
recipes.db.driver = org.h2.Driver
recipes.db.url = jdbc:h2:mem:recipes
# Hibernate properties
hibernate.dialect = org.hibernate.dialect.H2Dialect
hibernate.implicit_naming_strategy = org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
hibernate.format_sql = true
hibernate.show_sql = true
hibernate.hbm2ddl.auto = create-drop
spring.data.rest.basePath=/api/v1
资源目录
编辑:请参阅@lgaleazzi的答案以及随后的评论。基本上,删除UserHandler类可以修复它。尝试将以下方法添加到
SecurityConfig
:
@Override
public void configure(WebSecurity web) throws Exception {
// configuring here URLs for which security filters
// will be disabled (this is equivalent to using
// security="none")
web.ignoring().antMatchers("/login");
}
您可以在应用程序中指定不应应用身份验证的URL(对于静态资源也很有用)
在您的情况下,
/login
未被排除在身份验证范围之外,因此它会导致再次重定向到/login
,您会遇到一个恶性循环。尝试将以下方法添加到SecurityConfig
:
@Override
public void configure(WebSecurity web) throws Exception {
// configuring here URLs for which security filters
// will be disabled (this is equivalent to using
// security="none")
web.ignoring().antMatchers("/login");
}
您可以在应用程序中指定不应应用身份验证的URL(对于静态资源也很有用)
在您的情况下,
/login
未被排除在身份验证范围之外,因此它会导致再次重定向到/login
,从而导致恶性循环。堆栈跟踪说明了什么
查看UserHandler,您可以处理一个空的经过身份验证的对象,以及一个可以找到的用户。你不能处理匿名用户的情况。我想这就是问题所在
如果没有人经过身份验证,您将获得一个匿名用户的身份验证对象。您可以使用isAuthenticated()方法检查。但实际上您不必编写此代码,Spring Boot通过其默认配置可以很好地处理所有这些问题。堆栈跟踪说明了什么 查看UserHandler,您可以处理一个空的经过身份验证的对象,以及一个可以找到的用户。你不能处理匿名用户的情况。我想这就是问题所在
如果没有人经过身份验证,您将获得一个匿名用户的身份验证对象。您可以使用isAuthenticated()方法检查。但是您实际上不必编写此代码,Spring Boot在其默认配置下可以很好地处理所有这些问题。Hi Roman,所以当我添加该方法时,我会得到一个登录弹出窗口,而不是我的自定义登录页面,即使我尝试访问“/login”路由。现在它返回到仅显示:此页面不工作。localhost将您重定向了太多次。请尝试清除您的Cookie。ERR_TOO_MANY_redirects Hanks,Roman,我确认需要将登录URL添加到许可匹配器。在我的例子中,.antMatchers(“.css”、“.js”、“/pages/login/”).permitAll()“Hi Roman,所以当我添加该方法时,我会得到一个登录弹出窗口,而不是我的自定义登录页面,即使当我尝试访问“/login”路由时也是如此。现在,它又回到了仅显示:此页面不起作用。localhost将您重定向了太多次。请尝试清除您的cookie。ERR_TOO_MANY_redirects Hanks,Roman,我确认需要将登录URL添加到许可匹配器。在我的例子中,.antMatchers(“.css”、“.js”、“/pages/login/”.permitAll()”Hi-LGALAZI,因此堆栈跟踪中没有错误,只有一组hibernate控制台输出。当我运行调试器时,我看到它返回一个匿名用户,并抛出username not found异常,该异常通过重定向到登录页面来处理,我认为这是可以的。但是,我不明白的是,为什么登录页面根本没有呈现出来。因为您有一个异常处理程序,当抛出UserNotFoundException时,它会重定向到登录页面。因此,您加载登录页面,它查找用户,但没有找到,抛出异常,重定向到登录。一次又一次。这就是为什么您的浏览器出现“重定向太多”错误。您的UserHandler根本不允许匿名访问。如果你不允许匿名访问,没有人能够访问登录页面并进行身份验证。您应该删除该类,并让SecurityConfig类中的配置为您解决该问题。啊,这就解决了它!谢谢@lgalazzi!嗨,lgaleazzi,所以堆栈跟踪中没有错误,只有一堆hibernate控制台输出。当我运行调试器时,我看到它返回一个匿名用户,并抛出username not found异常,该异常通过重定向到登录页面来处理,我认为这是可以的。但是,我不明白的是,为什么登录页面根本没有呈现出来。因为您有一个异常处理程序,当抛出UserNotFoundException时,它会重定向到登录页面。因此,您加载登录页面,它查找用户,但没有找到,抛出异常,重定向到登录。一次又一次。这就是为什么您的浏览器出现“重定向太多”错误。您的UserHandler根本不允许匿名访问。如果你不允许匿名访问,没有人能够访问登录页面并进行身份验证。您应该删除该类,并让SecurityConfig类中的配置为您解决该问题。啊,这就解决了它!谢谢@lgalazzi!