Spring Security 的 Thymeleaf 授权不起作用[重复]

问题描述 投票:0回答:3

我在 Spring Boot 应用程序中使用 Spring Security,但 Thymeleaf 授权似乎无法正常工作。

我有带有以下代码的 Thymeleaf 模板:

<div class="container">
    <div class="row" sec:authorize="isAuthenticated()">
        <h2 style="color:green">User is Logged In</h2>
        <p sec:authentication="principal.username">username</p>
    </div>

    <div class="row" sec:authorize="!isAuthenticated()">
        <h2 style="color:red">User is Logged Out</h2>
    </div>

    <div class="row" sec:authorize="hasRole('ROLE_SUPERUSER')">
        <h2>This will only be displayed if authenticated user has role ROLE_SUPERUSER.</h2>
    </div>

    <div class="row" sec:authorize="hasRole('ROLE_ADMIN')">
        <h2>This will only be displayed if authenticated user has role ROLE_ADMIN.</h2>
    </div>

    <div class="row" sec:authorize="hasRole('ROLE_USER')">
        <h2>This will only be displayed if authenticated user has role ROLE_USER.</h2>
    </div>

    <div th:if="${#authorization.expression('hasRole(''ROLE_ADMIN'')')}">
        This will only be displayed if authenticated user has role ROLE_ADMIN.
    </div>

    <div th:if="${#authorization.expr('hasRole(''ROLE_ADMIN'')')}">
        This will only be displayed if authenticated user has role ROLE_ADMIN.
    </div>
</div>

示例取自:https://github.com/thymeleaf/thymeleaf-extras-springsecurity

但是,显示的唯一内容是

sec:authorize="isAuthenticated()"
sec:authorize="!isAuthenticated()"
,并且无论用户的角色如何,授权始终被忽略。

我的百里香配置是:

@Configuration
public class ThymeleafConfig {

    @Bean
    public TemplateResolver defaultTemplateResolver() {
        TemplateResolver resolver = new TemplateResolver();
        resolver.setResourceResolver(thymeleafResourceResolver());
        resolver.setPrefix("classpath:/templates/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode("HTML5");
        resolver.setCharacterEncoding("UTF-8");
        resolver.setCacheable(true);
        return resolver;
    }

    @Bean
    public SpringResourceResourceResolver thymeleafResourceResolver() {
        return new SpringResourceResourceResolver();
    }

    @Bean
    public SpringTemplateEngine templateEngine(TemplateResolver templateResolver) {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver);
        engine.addDialect(new SpringSecurityDialect());
        engine.addDialect(new LayoutDialect());
        return engine;
    }

    @Bean
    public ThymeleafViewResolver thymeleafViewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(templateEngine);
        resolver.setCharacterEncoding("UTF-8");
        resolver.setContentType("text/html");
        resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);
        return resolver;
    }

}

我对

thymeleaf-extras-springsecurity4
使用以下依赖项:

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity4</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>

版本

3.0.2.RELEASE
根本不起作用,并且
sec
命名空间总是被 Thymeleaf 忽略。
我的 Spring Boot 版本是
1.5.2.RELEASE

可能是什么原因?

更新。

configure(HttpSecurity http)
中的
SecurityConfig
方法如下所示:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().ignoringAntMatchers("/h2-console").disable()
            .authorizeRequests()
                .antMatchers("/webjars/**", "/static/**", "/images/**", "/**/favicon.ico").permitAll()
                .antMatchers("/heat/**", "/power/**", "/water/**").permitAll()

            // start allowing h2-console
                .antMatchers("/h2-console/**").permitAll();
            http.csrf().disable();
            http.headers().frameOptions().disable()
            // end allowing h2-console

            .and().authorizeRequests().antMatchers("/info").permitAll()
            .and().authorizeRequests().antMatchers("/users/**").authenticated()
            .and().authorizeRequests().antMatchers("/users/**").hasAnyAuthority("ADMIN", "SUPERUSER")

            .and().formLogin()
                    .loginPage("/login")
                    .permitAll()
            .and()
                    .logout()
                    .permitAll()
                    .deleteCookies("remove")
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("/")
                    .invalidateHttpSession(true)

            .and().exceptionHandling().accessDeniedPage("/access_denied");
}

并且来自

IndexController
的映射非常简单,它只是返回
login
模板:

@RequestMapping("/login")
public String loginForm() {
    return "login";
}
java spring-boot spring-security thymeleaf
3个回答
12
投票

版本说明: 由于新的安全限制,以下内容在 Thymeleaf 3.1+ 中不起作用。

解决任务的另一种方法是使用此语法来检查角色:

<div class="row" th:if="${#request.isUserInRole('SUPERUSER')}">
    <h2>This will only be displayed if authenticated user has role ROLE_SUPERUSER.</h2>
</div>

它不使用

sec
命名空间,实际上根本不需要 thymeleaf-extras-springsecurity4 依赖项来使用它。


3
投票

经过多次尝试不同的配置,我找到了解决方法。在这种情况下,

sec:authorize="hasAuthority('ADMIN')"
属性起作用:

<div class="row" sec:authorize="hasRole('ROLE_ADMIN')">
    <div class="col-md-10 col-md-offset-2">
        <h2>User Has Role Admin</h2>
    </div>
</div>
<div class="row" sec:authorize="hasAuthority('ADMIN')">
    <div class="col-md-10 col-md-offset-2">
        <h2>User Has Authority Admin</h2>
    </div>
</div>

User Has Authority Admin
标题呈现在页面上。

仍然不知道为什么

sec:authorize="hasRole('ROLE_ADMIN')"
属性不起作用,因为
thymeleaf-extras-springsecurity
GitHub 页面上建议将其作为示例: https://github.com/thymeleaf/thymeleaf-extras-springsecurity#using-the-attributes

希望这可以帮助某人,尽管问题仍然悬而未决。


1
投票

要尝试的事情:

1) 用

@EnableWebMvc
注释您的配置。

2) 将

ROLE_ADMIN
替换为
ADMIN
(其他也相应地)。

3)在您的控制器中,打印此内容以查看您当前的角色:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

Set<String> roles = authentication.getAuthorities().stream()
     .map(r -> r.getAuthority()).collect(Collectors.toSet());

System.out.println(roles);

如果这对您不起作用,也许可以尝试

getUserPrincipal()
中的
HttpServletRequest

简短地说:

我包含了我的 MVC 配置,以便您可以尝试最新的 Thymeleaf 和 Spring Security 版本。那里有一些额外的配置,因此您可以删除与您的项目无关的内容。

@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configuration) {

        configuration.enable();
    }

    @Bean
    public ThymeleafViewResolver viewResolver() {

        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setOrder(1);
        resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
        resolver.setTemplateEngine(templateEngine());
        return resolver;
    }

    @Bean
    public TemplateEngine templateEngine() {

        Set<ITemplateResolver> templateResolvers = new LinkedHashSet<>(1);
        templateResolvers.add(webTemplateResolver());

        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolvers(templateResolvers);
        Set<IDialect> dialects = new LinkedHashSet<>(2);
        dialects.add(new SpringSecurityDialect());
        dialects.add(new Java8TimeDialect());
        templateEngine.setAdditionalDialects(dialects);
        return templateEngine;
    }

    @Bean
    public ITemplateResolver webTemplateResolver() {

        SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
        resolver.setPrefix("/WEB-INF/thymeleaf/");
        resolver.setTemplateMode(TemplateMode.HTML);
        resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
        resolver.setSuffix(".html");
        resolver.setCacheable(false);
        resolver.setOrder(2);
        return resolver;
    }

    @Bean
    public ViewResolver tilesViewResolver() {

        UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
        viewResolver.setViewClass(TilesView.class);
        viewResolver.setOrder(0);
        return viewResolver;
    }

    @Bean
    public TilesConfigurer tilesConfigurer() {

        TilesConfigurer configurer = new TilesConfigurer();
        configurer.setDefinitions("/WEB-INF/**/views.xml");
        return configurer;
    }

    @Bean
    public LocalValidatorFactoryBean validator() {

        return new LocalValidatorFactoryBean();
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {

        registry.addViewController("/403");
        registry.addViewController("/404");
        registry.addViewController("/about");
        //edited for brevity
    }

    @Bean
    public ReloadableResourceBundleMessageSource messageSource() {

        ReloadableResourceBundleMessageSource source = new ReloadableResourceBundleMessageSource();
        source.setBasename("classpath:messages");
        source.setDefaultEncoding(StandardCharsets.UTF_8.name());
        return source;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(localeChangeInterceptor());
        registry.addInterceptor(themeChangeInterceptor());
        registry.addInterceptor(deviceResolverHandlerInterceptor());
        super.addInterceptors(registry);
    }

    @Bean
    public HandlerInterceptor localeChangeInterceptor() {

        LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
        interceptor.setParamName("lang");
        return interceptor;
    }

    @Bean
    public HandlerInterceptor themeChangeInterceptor() {

        ThemeChangeInterceptor interceptor = new ThemeChangeInterceptor();
        interceptor.setParamName("theme");
        return interceptor;
    }

    @Bean
    public ResourceBundleThemeSource themeSource() {

        ResourceBundleThemeSource themeSource = new ResourceBundleThemeSource();
        themeSource.setBasenamePrefix("theme-");
        return themeSource;
    }

    @Bean
    public PersistedThemeResolver themeResolver() {

        PersistedThemeResolver resolver = new PersistedThemeResolver();
        resolver.setDefaultThemeName("default");
        return resolver;
    }

    @Bean
    public HandlerInterceptor deviceResolverHandlerInterceptor() {

        return new DeviceResolverHandlerInterceptor();
    }

    @Bean
    public CookieLocaleResolver localeResolver() {

        CookieLocaleResolver resolver = new CookieLocaleResolver();
        resolver.setDefaultLocale(Locale.US);
        return resolver;
    }

    //removed custom bean declaration

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {

        argumentResolvers.add(new ServletWebArgumentResolverAdapter(new DeviceWebArgumentResolver()));
        super.addArgumentResolvers(argumentResolvers);
    }

    @Bean
    public Executor taskExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(100);
        executor.initialize();
        return executor;
    }
}

工作 pom 摘录:

    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf</artifactId>
        <version>3.0.2.RELEASE</version>
        <exclusions>
            <exclusion>
                <groupId>javassist</groupId>
                <artifactId>javassist</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring4</artifactId>
        <version>3.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        <version>3.0.0.RELEASE</version>
    </dependency>
© www.soinside.com 2019 - 2024. All rights reserved.