Выражения безопасности Spring для кода разрешения и имени

#java #spring #spring-security #jwt #spring-security-oauth2

#java #spring #spring-безопасность #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 (раздел полномочий).

введите описание изображения здесь

Одна из идей состоит в том, чтобы ввести коды разрешений, что-то вроде:

 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? Может быть, для достижения этого существует какой-то готовый подход?

Ответ №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;
    }
  

Комментарии:

1. Спасибо за ваш ответ. Прямо сейчас у меня следующая ошибка: не удается переопределить конечный метод createEvaluationContext из AbstractSecurityExpressionHandler<MethodInvocation> CustomMethodSecurityExpressionHandler.java Это Spring Security Core 4.0.3.RELEASE

2. теперь методы getTrustResolver() и getDefaultRolePrefix() оба не определены в моем customMethod securityexpressionhandler

3. Есть ли у вас какие-либо идеи, как это настроить? Спасибо

4. См. Обновление для исправления.

5. Спасибо, но, возможно, я делаю что-то неправильно — я не могу получить доступ к trustResolver, permissionEvaluator и roleHierarchy, потому что они являются частными и не могут быть доступны из моего customMethod securityexpressionhandler