如何使用 sec:authorize with thymeleaf 向特定用户授权 html 元素?

Posted

技术标签:

【中文标题】如何使用 sec:authorize with thymeleaf 向特定用户授权 html 元素?【英文标题】:How to authorize html elements to specific users with sec:authorize with thymeleaf? 【发布时间】:2021-09-27 21:14:08 【问题描述】:

我希望某些元素仅针对某些用户(而不是任何具有特定角色的用户)显示在前端。

为什么会这样:

<form sec:authorize="$principal.username.equals('A') " th:action="@'/saunojat/' + $saunoja.username + '/photo'" method="POST" enctype="multipart/form-data">
    <input type="file" name="photo" />
    <p>Kuvan tarina: <input type="text" name="description"/></p>
    <p> Asetetaanko kuva profiilikuvaksi?<input type="checkbox" name="isProfilepicture"/></p>
    <input type="submit" value="Send!"/>
</form>

但这不是:

<form sec:authorize="$principal.username.equals(saunoja.username) " th:action="@'/saunojat/' + $saunoja.username + '/photo'" method="POST" enctype="multipart/form-data">
    <input type="file" name="photo" />
    <p>Kuvan tarina: <input type="text" name="description"/></p>
    <p> Asetetaanko kuva profiilikuvaksi?<input type="checkbox" name="isProfilepicture"/></p>
    <input type="submit" value="Send!"/>
</form>

saunoja 是 Model 的一个属性。它是一个@Entity:

package projekti;

import java.util.List;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.jpa.domain.AbstractPersistable;

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Saunoja extends AbstractPersistable<Long> 

    private String username;

    private String password;

    private String firstName;

    private String lastName;

    @ElementCollection(targetClass = String.class, fetch = FetchType.EAGER)
    private List<String> roles;


错误:

白标错误页面 此应用程序没有 /error 的显式映射,因此您将其视为后备。

2021 年 7 月 20 日星期二 15:14:09 EEST 出现意外错误(类型=内部服务器错误,状态=500)。 模板解析时出错(模板:“类路径资源 [templates/saunoja.html]”) org.thymeleaf.exceptions.TemplateInputException:模板解析期间发生错误(模板:“类路径资源[模板/saunoja.html]”) 在 org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:241) 在 org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parseStandalone(AbstractMarkupTemplateParser.java:100) 在 org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:666) 在 org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098) 在 org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072) 在 org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:362) 在 org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:189) 在 org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1373) 在 org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1118) 在 org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1057) 在 org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) 在 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) 在 org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:626) 在 org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:733) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320) 在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126) 在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter.doFilterInternal(DefaultLogoutPageGeneratingFilter.java:52) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:216) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92) 在 org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) 在 org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) 在 org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358) 在 org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) 在 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) 在 org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) 在 org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) 在 org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) 在 org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589) 在 org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) 在 java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) 在 java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) 在 org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 在 java.base/java.lang.Thread.run(Thread.java:834) 原因:org.attoparser.ParseException:执行处理器“org.thymeleaf.extras.springsecurity5.dialect.processor.AuthorizeAttrProcessor”时出错(模板:“saunoja” - 第 58 行,第 15 列) 在 org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393) 在 org.attoparser.MarkupParser.parse(MarkupParser.java:257) 在 org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230) ... 86 更多 原因:org.thymeleaf.exceptions.TemplateProcessingException:执行处理器“org.thymeleaf.extras.springsecurity5.dialect.processor.AuthorizeAttrProcessor”时出错(模板:“saunoja” - 第 58 行,第 15 列) 在 org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:117) 在 org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95) 在 org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633) 在 org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1314) 在 org.thymeleaf.engine.TemplateHandlerAdapterMarkupHandler.handleOpenElementEnd(TemplateHandlerAdapterMarkupHandler.java:304) 在 org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler$InlineMarkupAdapterPreProcessorHandler.handleOpenElementEnd(InlinedOutputExpressionMarkupHandler.java:278) 在 org.thymeleaf.standard.inline.OutputExpressionInlinePreProcessorHandler.handleOpenElementEnd(OutputExpressionInlinePreProcessorHandler.java:186) 在 org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler.handleOpenElementEnd(InlinedOutputExpressionMarkupHandler.java:124) 在 org.attoparser.HtmlElement.handleOpenElementEnd(HtmlElement.java:109) 在 org.attoparser.HtmlMarkupHandler.handleOpenElementEnd(HtmlMarkupHandler.java:297) 在 org.attoparser.MarkupEventProcessorHandler.handleOpenElementEnd(MarkupEventProcessorHandler.java:402) 在 org.attoparser.ParsingElementMarkupUtil.parseOpenElement(ParsingElementMarkupUtil.java:159) 在 org.attoparser.MarkupParser.parseBuffer(MarkupParser.java:710) 在 org.attoparser.MarkupParser.parseDocument(MarkupParser.java:301) ... 88 更多 原因:java.lang.IllegalArgumentException:无法评估表达式'principal.username.equals(saunoja.username)' 在 org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:30) 在 org.thymeleaf.extras.springsecurity5.auth.AuthUtils$MvcAuthUtils.authorizeUsingAccessExpressionMvc(AuthUtils.java:353) 在 org.thymeleaf.extras.springsecurity5.auth.AuthUtils$MvcAuthUtils.access$100(AuthUtils.java:304) 在 org.thymeleaf.extras.springsecurity5.auth.AuthUtils.authorizeUsingAccessExpression(AuthUtils.java:173) 在 org.thymeleaf.extras.springsecurity5.dialect.processor.AuthorizeAttrProcessor.isVisible(AuthorizeAttrProcessor.java:73) 在 org.thymeleaf.standard.processor.AbstractStandardConditionalVisibilityTagProcessor.doProcess(AbstractStandardConditionalVisibilityTagProcessor.java:61) 在 org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74) ... 101 更多 原因:org.springframework.expression.spel.SpelEvaluationException:EL1008E:在“org.springframework.security.web.access.expression.WebSecurityExpressionRoot”类型的对象上找不到属性或字段“saunoja” - 可能不是公共的或无效的? 在 org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:217) 在 org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104) 在 org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:91) 在 org.springframework.expression.spel.ast.CompoundExpression.getValueRef(CompoundExpression.java:55) 在 org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:91) 在 org.springframework.expression.spel.ast.MethodReference.getArguments(MethodReference.java:164) 在 org.springframework.expression.spel.ast.MethodReference.getValueRef(MethodReference.java:81) 在 org.springframework.expression.spel.ast.CompoundExpression.getValueRef(CompoundExpression.java:70) 在 org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:91) 在 org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:117) 在 org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:308) 在 org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:26) ... 107 更多

【问题讨论】:

【参考方案1】:

我终于用 thymeleaf th:if 修复了它。

<div th:if="$saunoja.username == currentSaunoja.username">
    <form th:action="@'/saunojat/' + $saunoja.username + '/photo'" method="POST" enctype="multipart/form-data">
        <input type="file" name="photo" value="Valitse kuva"/>
        <p>Kuvan tarina: <input type="text" name="description"/></p>
        <p>Asetetaanko kuva profiilikuvaksi? <input type="checkbox" name="isProfilepicture"/></p>
        <input type="submit" value="Send!"/>
    </form>
</div>

currentSaunoja 是 Spring 安全认证中登录的 Saunoja。

【讨论】:

以上是关于如何使用 sec:authorize with thymeleaf 向特定用户授权 html 元素?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 <sec:authorize access="hasRole('ROLES)"> 来检查多个角色?

使用 sec:authorize 加载 javascript

在 jsp 页面中使用标签 <sec:authorize> 在 eclipse 中显示错误

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

sec:authorize from thymeleaf 可以用于多个角色吗

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