当前位置: 首页 > 面试题库 >

Thymeleaf的Spring Security的简单示例

严开宇
2023-03-14
问题内容

您好,我正在尝试按照一个简单的示例来做一个在此页面中找到的简单登录表单页面
http://docs.spring.io/autorepo/docs/spring-security/4.0.x/guides/form.html

问题是我每次尝试登录时都会遇到此错误: Expected CSRF token not found. Has your session expired?

当我收到此错误时,我按浏览器中的“后退”按钮,然后尝试再次登录,当我这样做时,我收到此错误: HTTP 403 - Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'

在教程页面中是以下消息: We use Thymeleaf to automatically add the CSRF token to our form. If we were not using Thymleaf or Spring MVCs taglib we could also manually add the CSRF token using <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

“所以因为我也使用百里香,所以我没有将该标签添加到我的页面中”

我找到了另一个解决方案,并且该方法有效,并且该解决方案将其添加到.csrf().disable()该解决方案的安全配置类中,但是我想这是要在我的页面中禁用csrf保护,并且我不想禁用这种类型的保护。

这是我的security-config类:

@Configuration
@EnableWebSecurity
public class ConfigSecurity extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER");
    }


    @Override
    protected void configure( HttpSecurity http ) throws Exception {
        http

        //.csrf().disable() is commented because i dont want disable this kind of protection 
        .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()                                    
                .permitAll();
    }
}

我的安全初始化程序:

public class InitSecurity extends AbstractSecurityWebApplicationInitializer {

    public InicializarSecurity() {
        super(ConfigSecurity .class);

    }
}

我的应用程序配置类,其中有我的百里香叶配置

@EnableWebMvc
@ComponentScan(basePackages = {"com.myApp.R10"})
@Configuration
public class ConfigApp extends WebMvcConfigurerAdapter{

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/css/**").addResourceLocations("/css/**");
        registry.addResourceHandler("/img/**").addResourceLocations("/img/**");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/**");
        registry.addResourceHandler("/sound/**").addResourceLocations("/sound/**");
        registry.addResourceHandler("/fonts/**").addResourceLocations("/fonts/**");
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Bean
      public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new       ReloadableResourceBundleMessageSource();
        messageSource.setBasenames("classpath:messages/messages");
        messageSource.setUseCodeAsDefaultMessage(true);
        messageSource.setDefaultEncoding("UTF-8");
        messageSource.setCacheSeconds(0);// # -1 : never reload, 0 always reload
        return messageSource;
    }
//  THYMELEAF

        @Bean 
        public ServletContextTemplateResolver templateResolver() {
            ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
            resolver.setPrefix("/WEB-INF/views/pagLogin/");
            resolver.setSuffix(".html");
            resolver.setTemplateMode("HTML5");
            resolver.setOrder(0);
            resolver.setCacheable(false);
            return resolver;
        }

        @Bean 
        public SpringTemplateEngine templateEngine() {
            SpringTemplateEngine engine  =  new SpringTemplateEngine();
            engine.setTemplateResolver( templateResolver() );
            engine.setMessageSource( messageSource() );



            return engine;
        }

        @Bean 
        public ThymeleafViewResolver thymeleafViewResolver() {
            ThymeleafViewResolver resolver  =  new ThymeleafViewResolver();

            resolver.setTemplateEngine( templateEngine() );
            resolver.setOrder(1);

            resolver.setCache( false );
            return resolver;
        }

        @Bean
        public SpringResourceTemplateResolver thymeleafSpringResource() {
            SpringResourceTemplateResolver vista = new SpringResourceTemplateResolver();
            vista.setTemplateMode("HTML5");
            return vista;
        }
}

我的应用程序配置初始化程序

public class InicializarApp extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }
@Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { ConfigApp .class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    protected Filter[] getServletFilters() {
        return new Filter[] { new HiddenHttpMethodFilter() };
    }
}

我的登录控制器类

@Controller
public class ControllerLogin {



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



         return "login";
    }

我的家庭控制器班

@Controller
public class HomeController {

        @RequestMapping(value = "/", method = RequestMethod.GET)
        public String home(Model model) {


        return "home";
        }


}

我的login.html

<html xmlns:th="http://www.thymeleaf.org" xmlns:tiles="http://www.thymeleaf.org">
  <head>
    <title tiles:fragment="title">Messages : Create</title>
  </head>
  <body>
    <div tiles:fragment="content">
        <form name="f" th:action="@{/login}" method="post">               
            <fieldset>
                <legend>Please Login</legend>
                <div th:if="${param.error}" class="alert alert-error">    
                    Invalid username and password.
                </div>
                <div th:if="${param.logout}" class="alert alert-success"> 
                    You have been logged out.
                </div>

                <label for="username">Username</label>
                    <input type="text" id="username" name="username"/>        
                <label for="password">Password</label>
                    <input type="password" id="password" name="password"/>

                <div class="form-actions">
                    <button type="submit" class="btn">Log in</button>
                </div>

                <!-- THIS IS COMMENTED it dont work beacuse i am already using thymeleaf <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>  -->


            </fieldset>
        </form>
    </div>


  </body>
</html>

我的home.html页面仅在我登录后显示,并且我登录的唯一方法是在Security
config类中放置一个.csrf()。disable(),但是我不想禁用该保护,如果我不这样做的话在我的安全配置类中,我收到了在此问题开头提到的错误。


问题答案:

从Spring Security文档

默认情况下,使用Java配置会启用CSRF保护。如果要禁用CSRF,则可以在下面看到相应的Java配置。有关如何配置CSRF保护的更多自定义信息,请参考csrf()的Javadoc。

并且,启用CSRF保护后

最后一步是确保在所有PATCH,POST,PUT和DELETE方法中都包含CSRF令牌。

在您的情况下:

  • 您默认情况下启用了CSRF保护(因为您使用的是Java配置),
  • 您正在使用HTTP POST提交登录表单,并且
  • 在登录表单中不包含CSRF令牌。因此,您的登录请求在提交时被拒绝,因为CSRF保护筛选器无法在传入请求中找到CSRF令牌。

您已经确定了可能的解决方案:

  1. 禁用CSRF保护为http.csrf().disable();要么
  2. 在登录表单中包含CSRF令牌作为隐藏参数。

由于您正在使用Thymeleaf,因此您将必须在登录页面的HTML模板中执行以下操作:

<form name="f" th:action="@{/login}" method="post">               
  <fieldset>

    <input type="hidden" 
           th:name="${_csrf.parameterName}" 
           th:value="${_csrf.token}" />

    ...
  </fieldset>
</form>

请注意,您必须使用 th:action HTML而不是HTML, action 因为Thymeleaf
CSRF处理器只会在前者中起作用。

您可以将表单提交方法更改为GET仅解决问题,但是不建议这样做,因为用户将要在表单中提交敏感信息。

我通常创建一个Thymeleaf片段,然后在所有带有表单的页面中使用该片段,以生成包含CSRF令牌的表单标记。这减少了整个应用程序的样板代码。

使用@EnableWebMvcSecurity代替@EnableWebSecurity启用带有Thymeleaf标签的CSRF令牌自动注入。还可以<form th:action>代替<form action>Spring 3.2+和Thymeleaf
2.1+使用,以强制Thymeleaf自动将CSRF令牌包括为隐藏字段(来源Spring
JIRA)。



 类似资料:
  • 本文向大家介绍Spring Boot配置Thymeleaf(gradle)的简单使用,包括了Spring Boot配置Thymeleaf(gradle)的简单使用的使用技巧和注意事项,需要的朋友参考一下 最近项目用到了Spring Boot ,但是在控制器返回html视图并渲染参数的时候,存在了疑问。后面考虑用Thymeleaf ,感觉真的不错,下面分享给大家 总共四步: jar 引入 控制器参数

  • 问题内容: 使用Javascript最简单的SOAP示例是什么? 为了尽可能有用,答案应该是: 具有功能性(换句话说,实际上有效) 发送至少一个可以在代码中其他位置设置的参数 处理至少一个可以在代码的其他位置读取的结果值 使用大多数现代浏览器版本 在不使用外部库的情况下尽可能清晰明了 问题答案: 这是我可以创建的最简单的JavaScript SOAP客户端。

  • 问题内容: 请帮助我,如果有人可以给我一个例子,如何在cakephp 2.3.0中使用ajax,一个例子是这样的 当我单击链接时,具有ID的div 会发生变化。我如何使用cakephp 2.3.0做到这一点? 问题答案: 请参见以下示例:

  • 实例一、使用HTTP协议对外提供Web服务 创建http_test.php文件(位置任意,能引用到Workerman/Autoloader.php即可,下同) <?php use WorkermanWorker; require_once __DIR__ . '/Workerman/Autoloader.php'; // 创建一个Worker监听2345端口,使用http协议通讯 $http_w

  • 问题内容: 这应该很简单,但是我真的很难做到正确。我需要的只是一个简单的ttk ComboBox,它可以在选择更改时更新变量。 在下面的示例中,我需要在每次进行新选择时自动更新变量的值。 问题答案: 只需将虚拟事件绑定到Combobox小部件:

  • 本文章将介绍Thymeleaf标准表达式语法中的概念。 学习如何在Thymeleaf模板中显示对象(Bean)的属性值。 已经将类的bean已经设置为名称为的上下文模型。 为这些和属性添加一些格式,学习使用和实用程序对象的定义。 最后,修改模板以获得一个合理的静态原型(例如,通过一些原型数据替换并显示结果)。 如果要上机实践,请参考:Thymeleaf+SpringMVC5示例项目。这里不再重复创

  • 问题内容: 因此,我最近一直在尝试了解Socket.io,但是我不是一个非常出色的程序员,并且几乎可以在网络上找到的每个示例(相信我已经花了数小时的时间)都包含使事情变得复杂的额外内容。许多示例都会使我感到困惑,或者连接到一些奇怪的数据库,或者使用coffeescript或大量的JS库将事情弄乱了。 我很乐意看到一个基本的,可以正常运行的示例,其中服务器仅每10秒向客户端发送一条消息,说明现在几点

  • 本文向大家介绍android音乐播放简单实现的简单示例(MediaPlayer),包括了android音乐播放简单实现的简单示例(MediaPlayer)的使用技巧和注意事项,需要的朋友参考一下 利用MediaPlayer完成一个最简单的音乐播放。这个基本的控制掌握后,可直接利用为背景乐的控制。 为了能够实现播放,在界面方面,我们需要三个控制按钮,分别是:Play(播放)、Pause(暂停)、St