java - Spring MVC、Spring 安全 : Unable to load login template

标签 java spring spring-mvc spring-boot spring-security

当访问任何路由时,我会被重定向到我的登录页面,包括访问我的登录页面,这是预期的。现在的问题是登录页面甚至无法加载。我已经配置了完成这项工作所需的 Controller 方法、处理程序、模板配置和安全配置,但我得到的只是以下错误:

http://localhost:8080/login?errorMessage=Login+to+use+the+app

enter image description here

UserController.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";
    }
}

UserHandler.java

@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";
    }
}

TemplateConfig.java

@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;
    }
}

SecurityConfig.java

@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) {};
            }
        };
    }
}

application.properties

# 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

资源目录

enter image description here

编辑:请参阅@lgaleazzi 的回答以及后面的评论。本质上,删除 UserHandler 类可以修复它。

最佳答案

堆栈跟踪说明了什么?

查看您的 UserHandler,您处理一个空的经过身份验证的对象,以及您可以找到的用户。您不处理匿名用户发生的事情。我认为这就是问题所在。

如果没有人经过身份验证,您将获得匿名用户的身份验证对象。您可以使用 isAuthenticated() 方法进行检查。但实际上您不必编写此代码,Spring Boot 通过其默认配置很好地处理了所有这些问题。

关于java - Spring MVC、Spring 安全 : Unable to load login template,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49591541/

相关文章:

java - Mockito,无法初始化 JNDI 或来自 servlet 容器的任何内容

java - 返回 CompletableFuture 的 Spring Transactional 方法

java - SpringBoot注入(inject): OK with app,但没有经过测试

java - 未找到 HTTP 请求与 URI 的映射

java - 如何在 Netbeans 控制台中打印希伯来语字符

java - Dozer:映射列表时类强制转换异常

java - class.forName,寻找不同项目中的类,抛出ClassNotFoundException

java - 无法在 Spring Boot 中从 vcap_services 中用户提供的凭据检索

java - 我如何验证一个人是否上传了文件

java - Spring Rest 操作将响应转换为类