【问题标题】:Spring Security expressions for permission code and name权限代码和名称的 Spring Security 表达式
【发布时间】:2017-02-11 07:47:49
【问题描述】:

在我的 Spring Security 项目中,我有一个使用 @PreAuthorize 注释保护的以下方法:

@PreAuthorize("hasAnyAuthority('PERMISSION_UPDATE_OWN_DECISION', 'PERMISSION_UPDATE_ANY_DECISION')")
@RequestMapping(value = "/{decisionId}/update", method = RequestMethod.POST)
public DecisionResponse updateDecision(@PathVariable @NotNull @DecimalMin("0") Long decisionId, @Valid @RequestBody UpdateDecisionRequest decisionRequest) {
    ....
}

我还将 Spring OAuth2 与 JWT 令牌一起使用,并将所有权限存储在此令牌中。现在,我使用了很长的权限名称,例如 PERMISSION_UPDATE_OWN_DECISION,并希望替换它们以显着减少 JWT 令牌大小(权限部分)。

其中一个想法是引入权限代码,例如:

1, PERMISSION_UPDATE_OWN_DECISION
2, PERMISSION_UPDATE_ANY_DECISION

其中1 是权限代码,PERMISSION_UPDATE_OWN_DECISION 是权限名称。

但我不想直接使用这些代码,因为它会降低我的代码的可读性,例如:

@PreAuthorize("hasAnyAuthority('1', '2')")

我想使用一些允许我根据真实权限名称检索此代码的东西,例如:

@PreAuthorize("hasAnyAuthority(getCode('PERMISSION_UPDATE_OWN_DECISION')), getCode('PERMISSION_UPDATE_ANY_DECISION'))")

如何使用 Spring Security 和 Spring Security Expressions 正确实现这一点?可能有一些预先构建的方法来实现这一点?

【问题讨论】:

    标签: java spring spring-security jwt spring-security-oauth2


    【解决方案1】:

    首先,您需要继承 MethodSecurityExpressionRoot 并使用您的逻辑创建自定义类。

    public class CustomMethodSecurityExpressionRoot extends MethodSecurityExpressionRoot {
        public boolean hasAnyAuthorityWithCodes(String... codes) {
             String[] ids = // Your custom Logic to get Ids from Code
    
             return hasAnyAuthority(ids);
        }
    
    }
    

    然后继承 DefaultMethodSecurityExpressionHandler 并覆盖它的 createEvaluationContext 方法。

    @Override
    public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
        MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(auth, mi, parameterNameDiscoverer);
        MethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(auth);
        root.setTrustResolver(trustResolver);
        root.setPermissionEvaluator(permissionEvaluator);
        root.setRoleHierarchy(roleHierarchy);
        ctx.setRootObject(root);
    
        return ctx;
    }
    

    最后你可以在你的配置中使用这个自定义的DefaultMethodSecurityExpressionHandler

    <global-method-security>
      <expression-handler ref="customMethodSecurityExpressionHandler"/>
    </global-method-security>
    

    并使用

    @PreAuthorize("hasAnyAuthorityWithCodes('PERMISSION_UPDATE_OWN_DECISION','PERMISSION_UPDATE_ANY_DECISION')")
    

    更新

    子类 DefaultMethodSecurityExpressionHandler 并覆盖 createSecurityExpressionRoot 方法

        protected MethodSecurityExpressionOperations createSecurityExpressionRoot(
            Authentication authentication, MethodInvocation invocation) {
            MethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(
                    authentication);
            root.setThis(invocation.getThis());
            root.setTrustResolver(trustResolver);
            root.setPermissionEvaluator(permissionEvaluator);
            root.setRoleHierarchy(roleHierarchy);
            root.setDefaultRolePrefix(defauleRolePrefix);
    
            return root;
        }
    

    【讨论】:

    • 感谢您的回答。现在我有以下错误:无法从 AbstractSecurityExpressionHandler CustomMethodSecurityExpressionHandler.java 覆盖最终方法 createEvaluationContext 这是 Spring Security Core 4.0.3.RELEASE
    • 现在 getTrustResolver() 和 getDefaultRolePrefix() 方法在我的 CustomMethodSecurityExpressionHandler 中都未定义
    • 你知道如何调整它吗?谢谢
    • 查看更新以修复。
    • 谢谢,但也许我做错了什么 - 我无法访问 trustResolver、permissionEvaluator 和 roleHierarchy,因为它们是私有的,无法从我的 CustomMethodSecurityExpressionHandler 访问
    猜你喜欢
    • 2016-08-25
    • 2014-06-02
    • 2011-09-15
    • 2011-12-24
    • 2018-12-30
    • 1970-01-01
    • 2011-10-14
    • 2016-08-11
    • 2014-04-05
    相关资源
    最近更新 更多