Thymeleaf 和 Spring 引导以及 Spring 安全性不起作用

Posted

技术标签:

【中文标题】Thymeleaf 和 Spring 引导以及 Spring 安全性不起作用【英文标题】:Thymeleaf and Spring boot and Spring security not working 【发布时间】:2019-07-27 14:14:44 【问题描述】:

我正在尝试将 thymeleaf、spring security 和 spring boot 一起运行,但我不确定如何将它们集成在一起,因为我在 spring security 阻止静态的 href 等方面遇到了一些问题。

问题是提交登录后它没有通过安全配置的成功处理程序,所以我认为视图没有正确映射。

SecurityConfig 如下所示:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter 

    private static final Logger logger = LogManager.getLogger(SecurityConfig.class);

    @Autowired
    private LoggingAccessDeniedHandler accessDeniedHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http
            .authorizeRequests()
                .antMatchers(
                        "/",
                        "/js/**",
                        "/css/**",
                        "/img/**",
                        "/webjars/**").permitAll()
                .antMatchers("/user/**").hasRole("USER")
                .anyRequest().authenticated()
            .and()
            .formLogin()
                .loginPage("/login")
                .successHandler(myAuthenticationSuccessHandler())
                .permitAll()
            .and()
            .logout()
                .invalidateHttpSession(true)
                .clearAuthentication(true)
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .logoutSuccessUrl("/login?logout")
                .permitAll()
            .and()
            .exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler);
    

    @Override
    public void configure(WebSecurity web) throws Exception 
        web
            .ignoring()
            .antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**","/vendor/**","/fonts/**");
    

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception 
        logger.info("configuring");
        auth.inMemoryAuthentication()
            .withUser("user").password("password").roles("USER")
            .and()
            .withUser("manager").password("password").roles("MANAGER");
    

    @Bean
    public AuthenticationSuccessHandler myAuthenticationSuccessHandler()
        logger.info("GOt into the thingie");
        return new MySimpleUrlAuthenticationSuccessHandler();
    


class MySimpleUrlAuthenticationSuccessHandler
    implements AuthenticationSuccessHandler 

    private static final Logger logger = LogManager.getLogger(SecurityConfig.class);

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
        HttpServletResponse response, 
        Authentication authentication)
        throws IOException 

        handle(request, response, authentication);
        clearAuthenticationAttributes(request);
    

    protected void handle(HttpServletRequest request,
        HttpServletResponse response, Authentication authentication)
        throws IOException 

        logger.info("got here");
        String targetUrl = determineTargetUrl(authentication);

        if (response.isCommitted()) 
            logger.info(
                "Response has already been committed. Unable to redirect to " + targetUrl);
            return;
        

        redirectStrategy.sendRedirect(request, response, targetUrl);
    

    protected String determineTargetUrl(Authentication authentication) 
        logger.info("got here in target");
        boolean isUser = false;
        boolean isAdmin = false;
        Collection<? extends GrantedAuthority> authorities
            = authentication.getAuthorities();
        for (GrantedAuthority grantedAuthority : authorities) 
            if (grantedAuthority.getAuthority().equals("ROLE_USER")) 
            isUser = true;
            break;
             else if (grantedAuthority.getAuthority().equals("ROLE_ADMIN")) 
                isAdmin = true;
                break;
            
        

        if (isUser) 
            return "/homepage.html";
         else if (isAdmin) 
            return "/console.html";
         else 
            throw new IllegalStateException();
        
    

    protected void clearAuthenticationAttributes(HttpServletRequest request) 
        HttpSession session = request.getSession(false);
        if (session == null) 
            return;
        
        session.removeAttribute
            (WebAttributes.AUTHENTICATION_EXCEPTION);
    

    public void setRedirectStrategy(RedirectStrategy redirectStrategy) 
        this.redirectStrategy = redirectStrategy;
    
    protected RedirectStrategy getRedirectStrategy() 
        return redirectStrategy;
    

控制器如下所示:

@RequestMapping(value = "/", method= RequestMethod.GET)
public String login(Model model)
    return "login";


@RequestMapping(value = "/login", method= RequestMethod.GET)
public String loginSucc(Model model)
    return "predictions";

在 src/main/resources/templates 下是:

templates html

从上图中可以看出,我在模板下拥有所有必需的 html 页面。 ** Predictions.html 是否也存在,只是未包含在屏幕截图中。 最后 login.html 看起来像这样:

<!-- Login Form -->
<form th:action="@/login" method="post">
    <input type="text" id="login" class="fadeIn second" name="login" placeholder="login">
    <input type="text" id="password" class="fadeIn third" name="login" placeholder="password">
    <input type="submit" class="fadeIn fourth" value="Log In">
</form>

在获取登录页面并输入任何用户名和密码后,它会重定向到预测页面。它显然没有进行身份验证,因为没有检查用户名/密码,并且在预测页面中我打印出刚刚没有出现的用户名(空白)。我已根据下面的评论添加了 sn-p。但这并没有什么区别。

从“login.html”重定向后的预测页面: enter image description here

【问题讨论】:

POST 时到底发生了什么? 编辑了帖子以显示究竟发生了什么并添加了一张图片。它重定向到预测页面,但它没有通过身份验证,因为它显示登录?错误,但我可以看到预测页面。 【参考方案1】:

也覆盖此方法 configure(WebSecurity web) 并修改如下代码

 @Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http
                .authorizeRequests()
                .antMatchers("/user/**").hasRole("USER")
                .anyRequest().authenticated()
                .and()
                .formLogin()
            .loginPage("/login")
            .defaultSuccessUrl("/module",true)
            .failureUrl("/login?error=true")
        .permitAll();// others according to your need
    
      @Override
        public void configure(WebSecurity web) throws Exception 
            web
                    .ignoring()
                    .antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**","/vendor/**","/fonts/**");
        

【讨论】:

只尝试了这段代码,它不起作用。我可以在日志中看到:“.ssUserDetailsS​​erviceAutoConfiguration:使用生成的安全密码:100fc149-c427-4010-8da9-1d278fa12d17”和创建过滤器链:Ant [pattern='/resources/**'], [] [pattern=' /static/**']、[pattern='/css/**']、[]等。但所看到的只是预测页面和显示 localhost:8090/login 的 url,而没有实际触发 login.html 页面 登录成功后实际想去哪里? 我希望它转到templates/predictions.html下的predictions.html。我不希望在 URL 栏中持续显示登录信息,我希望成功登录。我看不到根据上述日志行记录的成功处理程序中的任何内容,当前当它重定向到预测时,URL 栏显示登录错误并且我没有得到登录的用户名(页面应该说 Hello!'User')因为我相信它实际上根本没有登录和验证。不知怎的,它绕过了它 首先,我不明白你为什么使用MySimpleUrlAuthenticationSuccessHandler 类? 2、角色不匹配。你应该首先阅读文档。 你可以以baeldung.com/spring-security-login为例【参考方案2】:

问题在于输入类型名称是登录名而不是用户名:

这解决了它:

  <form th:action="@/login" method="post">
            <input type="text" id="username" class="fadeIn second" name="username" placeholder="login">
            <input type="text" id="password" class="fadeIn third" name="password" placeholder="password">

【讨论】:

以上是关于Thymeleaf 和 Spring 引导以及 Spring 安全性不起作用的主要内容,如果未能解决你的问题,请参考以下文章

带有 Thymeleaf、Spring 引导、Mysql 的 Ckeditor

springbooot2 thymeleaf 配置以及加载资源文件。Cannot find template location: classpath:/templates/ (please add s

Thymeleaf 或 JSP:Spring Boot 哪个更好?

CSS 文件找不到 thymeleaf Spring Boot

Spring Boot + Thymeleaf + webjars Bootstrap 4

如何使用 Thymeleaf 在 Spring Boot 应用程序中正确缓存数据