#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