我需要发明一种新类型的注释,其中一个字段是Spring Expression Language(aka SpEL)表达式字符串。
经过一些谷歌搜索和检查现有的类,我已经发现评估表达式的方式可能就像这样(如果我错了,请纠正我):
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("isAnonymous()"); // well, this is only an example
SecurityExpressionRoot context = ... obtaining the instance of subclass of SecurityExpressionRoot ...
System.out.println(exp.getValue(context)); // just an example
但问题是:最适合我的情况MethodSecurityExpressionRoot是package-local。甚至还有task about making it public in Spring Security JIRA一年没有得到开发人员的关注。
即使它不是本地包,我仍然不清楚在哪里获取setTrustResolver
,setRoleHierarchy
和setPermissionEvaluator
SecurityExpressionRoot
方法的对象这个类似乎是正常运作所必需的。
所以,我的问题是:你如何正确地获得正确的SecurityExpressionRoot
- 子类实例以及如何用必需的对象填充它?
答案 0 :(得分:0)
我设法在没有任何新注释的情况下实现了这一点。您需要做的第一件事是将菜单项包装在sec:authorize标记中,其中sec命名空间来自spring security taglibs。我们使用:
<sec:authorize access="hasRole('${menuItem.permission}')"></sec:authorzie>
其中${menuItem.permission}
是当前permission
对象的menuItem
字段(我们循环访问我们从服务器检索到的menuItems)。 SpEl hasRole()
由org.springframework.security.access.expression.SecurityExpressionOperations
类中的spring实现。
这不会给你带来安全感,它只会使gui变得更好。服务器还需要使用以下内容进行保护:
@PreAuthorize("hasRole('...')")
@PreAuthorize
注释也来自spring security,它会阻止客户端在服务器上执行方法,除非用户具有给定的角色。为了完成这项工作,我们必须实施org.springframework.security.cas.userdetails.AbstractCasAssertionUserDetailsService
。大多数身份管理服务器都存在类似的类。我们还必须实现org.jasig.services.persondir.support.ldap.LdapPersonAttributeDao
,但我们也在使用ldap。 YMMV。
答案 1 :(得分:0)
我正在解决同样的问题。我有一个菜单项列表。每个菜单项都包含一个安全表达式字符串(SpEl)。我试图使用@PostFilter(“filterObject.securityExpression”),但我无法弄清楚如何评估SpEl字符串中的SpEl字符串。
所以我最终得到了自定义评估器bean。受到org.thymeleaf.extras.springsecurity4.auth.AuthUtils
的启发评估者使用相同的SecurityExpressionHandler作为Web安全过滤器。这意味着必须为评估环境提供请求和响应。但这并不复杂,因为Spring将这些值注入控制器方法。
求值:
@Component
public class WebSecurityExpressionEvaluator {
private static final FilterChain EMPTY_CHAIN = (request, response) -> {
throw new UnsupportedOperationException();
};
private final List<SecurityExpressionHandler> securityExpressionHandlers;
public WebSecurityExpressionEvaluator(List<SecurityExpressionHandler> securityExpressionHandlers) {
this.securityExpressionHandlers = securityExpressionHandlers;
}
public boolean evaluate(String securityExpression, HttpServletRequest request, HttpServletResponse response) {
SecurityExpressionHandler handler = getFilterSecurityHandler();
Expression expression = handler.getExpressionParser().parseExpression(securityExpression);
EvaluationContext evaluationContext = createEvaluationContext(handler, request, response);
return ExpressionUtils.evaluateAsBoolean(expression, evaluationContext);
}
@SuppressWarnings("unchecked")
private EvaluationContext createEvaluationContext(SecurityExpressionHandler handler, HttpServletRequest request, HttpServletResponse response) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
FilterInvocation filterInvocation = new FilterInvocation(request, response, EMPTY_CHAIN);
return handler.createEvaluationContext(authentication, filterInvocation);
}
private SecurityExpressionHandler getFilterSecurityHandler() {
return securityExpressionHandlers.stream()
.filter(handler -> FilterInvocation.class.equals(GenericTypeResolver.resolveTypeArgument(handler.getClass(), SecurityExpressionHandler.class)))
.findAny()
.orElseThrow(() -> new IllegalStateException("No filter invocation security expression handler has been found! Handlers: " + securityExpressionHandlers.size()));
}
}
用作控制器方法:
@ModelAttribute("adminMenuItems")
public List<AdminMenuItem> getMenuItems(HttpServletRequest request, HttpServletResponse response) {
List<AdminMenuItem> menuItems = ...
return menuItems.stream().filter(item -> evaluator.evaluate(item.getSecurityExpression(), request, response)).collect(toList());
}