在 sec:authorize thymeleaf 标记中连接字符串和变量

Posted

技术标签:

【中文标题】在 sec:authorize thymeleaf 标记中连接字符串和变量【英文标题】:Concatenate string and variable in sec:authorize thymeleaf tag 【发布时间】:2015-03-01 14:41:10 【问题描述】:

我正在尝试使用 thymeleaf 标签 sec:authorize :

sec:authorize="hasPermission(#user, 'listagem_$item.simpleName')"

但是当我部署和运行项目时,字符串listagem_$item.simpleName没有被处理,内容也没有显示出来。

任何人都知道能够在 sec:authorize 标记内进行这种连接的正确方法吗?

更新

尝试后:

<span th:text="|hasPermission(#user, 'listagem_$item.simpleName')|"></span>

看到我得到了正确的结果,我尝试将表达式:|hasPermission(#user, 'listagem_$item.simpleName')| 传输到 sec:authorize 标记,如下所示:

<li th:each="item : $menu" sec:authorize="|hasPermission(#user, 'listagem_$item.simpleName')|">

但我收到此错误:

    Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: An error happened trying to parse Spring Security access expression "|hasPermission(#user, 'listagem_$item.simpleName')|" (private/home:40)] with root cause

org.springframework.expression.spel.SpelParseException: EL1069E:(pos 0): missing expected character '|'
        at org.springframework.expression.spel.standard.Tokenizer.process(Tokenizer.java:194)
        at org.springframework.expression.spel.standard.Tokenizer.<init>(Tokenizer.java:84)
        at org.springframework.expression.spel.standard.InternalSpelExpressionParser.doParseExpression(InternalSpelExpressionParser.java:121)
        at org.springframework.expression.spel.standard.SpelExpressionParser.doParseExpression(SpelExpressionParser.java:60)
        at org.springframework.expression.spel.standard.SpelExpressionParser.doParseExpression(SpelExpressionParser.java:32)
        at org.springframework.expression.common.TemplateAwareExpressionParser.parseExpression(TemplateAwareExpressionParser.java:76)
        at org.springframework.expression.common.TemplateAwareExpressionParser.parseExpression(TemplateAwareExpressionParser.java:62)
        at org.thymeleaf.extras.springsecurity3.auth.AuthUtils.authorizeUsingAccessExpression(AuthUtils.java:186)
        at org.thymeleaf.extras.springsecurity3.dialect.processor.AuthorizeAttrProcessor.isVisible(AuthorizeAttrProcessor.java:100)
        at org.thymeleaf.processor.attr.AbstractConditionalVisibilityAttrProcessor.processAttribute(AbstractConditionalVisibilityAttrProcessor.java:58)
        at org.thymeleaf.processor.attr.AbstractAttrProcessor.doProcess(AbstractAttrProcessor.java:87)
        at org.thymeleaf.processor.AbstractProcessor.process(AbstractProcessor.java:212)
        at org.thymeleaf.dom.Node.applyNextProcessor(Node.java:1016)
        at org.thymeleaf.dom.Node.processNode(Node.java:971)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:672)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:655)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:672)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:655)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:672)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:655)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:672)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:655)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:672)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:655)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:672)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:655)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:672)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:655)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.Document.process(Document.java:93)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1155)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1060)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1011)
        at org.thymeleaf.spring4.view.ThymeleafView.renderFragment(ThymeleafView.java:335)
        at org.thymeleaf.spring4.view.ThymeleafView.render(ThymeleafView.java:190)
        at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1228)
        at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1011)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:955)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
        at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
        at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:146)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
        at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
        at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
        at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)

我在这里缺少什么?

【问题讨论】:

你试过 $'listagem_'+item.simpleName 吗? @MartinFrey 是的,也不行。 listagem_ 是您要传递的单独变量吗?如果是,那么正确的 concat 将是 $'listagem_'+$item.simpleName @Aeseir 这不起作用。我得到错误:org.springframework.expression.spel.SpelParseException: EL1043E:(pos 22): Unexpected token. Expected 'rparen())' but was 'lcurly()'. listagem_ 你传入的变量也是如此,因为我以前在代码中没有见过它 【参考方案1】:

在我的例子中,我在变量中包含了用户角色名称。我终于设法让它工作了

<div th:if="$#authorization.expression('hasRole('''+objectDTO.roleName+''')')"></div>

这个想法来自这里(注意双单引号以转义名称)https://github.com/thymeleaf/thymeleaf-extras-springsecurity#using-the-expression-utility-objects

【讨论】:

【参考方案2】:

我在字符串连接和 thymeleaf 中的 sec:authorize 属性方面遇到了类似问题,尽管情况不完全相同,但它可能对遇到此问题的其他人有用。

我想根据用户(主体)权限限制某些元素的可见性。在此示例中,我有一个页面显示客户详细信息,其他用户可以访问该页面,但只有“客户经理”可以看到电子邮件地址。当我对权限字符串进行硬编码时,一切正常:

<th:block sec:authorize="hasAuthority('VIEW_USER_EMAIL')"> ... </th:block>

我宁愿不要在我的模板上散布随机字符串,因为它们可能在某些时候被重构并且容易出错。我有一个包含public static final String 字段负载的类,称为Permission。我本来希望使用enum,但无法从@PreAuthorize@Secured 之类的注释中引用,我在应用程序see this question for more details 的其他地方使用了这些注释。

解决方案是从模板的表​​达式中引用我的Permission 类。这可以使用SpEL type operator T() 来实现。通过尝试错误直到最终成功,我在正确获取语法时遇到了很多麻烦:

<th:block sec:authorize="hasAuthority(T(com.example.app.Permission).VIEW_USER_EMAIL)"> ... </th:block>

这意味着如果Permission 类或VIEW_USER_EMAIL 字段不存在或有错字,将引发异常。与静默失败并可能拒绝访问相比,这是一个巨大的改进。

以下是我之前的一些尝试:

sec:authorize="hasAuthority('$T(com.example.app.Permission).VIEW_USER_EMAIL')" sec:authorize="hasAuthority($T(com.example.app.Permission).VIEW_USER_EMAIL)" sec:authorize="$hasAuthority('T(com.example.app.Permission).VIEW_USER_EMAIL')"

它看起来像 thymeleaf Spring Security Dialect 从您传入的任何表达式中剥离前导 $ 和尾随 并尝试评估整个表达式,这就是为什么任何形式的连接都可能不起作用的原因。

供参考,这是我的Permission 课程:

public final class Permission public static final String VIEW_USER_EMAIL = "VIEW_USER_EMAIL";

【讨论】:

我还遇到了另一种情况,我需要在表达式中使用变量并且无法转义它,解决方案是使用三个单引号:th:if="$#authorization.expression('hasAuthority(''' + someObject.permissionString + ''')')"

以上是关于在 sec:authorize thymeleaf 标记中连接字符串和变量的主要内容,如果未能解决你的问题,请参考以下文章

sec:authorize 在 thymeleaf 视图中为 isAuthenticated() 和 isAnonymous() 返回 true

sec:authorize 在 thymeleaf 视图中为 isAuthenticated() 和 isAnonymous() 返回 true

sec:authorize 在 Spring 启动应用程序中使用 Thymeleaf 时未按预期工作

thymeleaf.extras.springsecurity4 sec:authorize 不起作用

Spring Security - Thymeleaf - 我可以在 sec:authorize 标签中评估 SPEL 表达式吗?

Spring Security Role Hierarchy 不适用于 Thymeleaf sec:authorize