用于权限代码和名称的Spring Security表达式

时间:2016-10-03 11:19:02

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

在我的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令牌大小(权限部分)。

enter image description here

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

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正确实现此功能?可能有一些预先建立的方法来实现这个目标吗?

1 个答案:

答案 0 :(得分: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;
    }