不幸的是,RolesAllowedDynamicFeature 似乎不支持使用编程 API 创建的资源。如果您查看source for RolesAllowedDynamicFeature,您会发现它会查找资源方法和/或资源类上的注释以确定资源/方法是否应附加到filter that handles the authorization。
我能想到的最好方法就是在Inflector 中进行授权。您可以在我链接到的源代码中看到,处理授权的过滤器并没有真正做太多。它只是检查SecurityContext 是否允许角色。您可以使用Inflector 中的逻辑。例如
public static class AuthorizationInflector
implements Inflector<ContainerRequestContext, Response> {
private final String[] rolesAllowed;
private final Inflector<ContainerRequestContext, Response> delegate;
protected AuthorizationInflector(String[] rolesAllowed,
Inflector<ContainerRequestContext, Response> delegate) {
this.rolesAllowed = (rolesAllowed != null) ? rolesAllowed : new String[] {};
this.delegate = delegate;
}
@Override
public Response apply(ContainerRequestContext context) {
applyAuthorization(context);
return this.delegate.apply(context);
}
private void applyAuthorization(ContainerRequestContext requestContext) {
if (rolesAllowed.length > 0 && !isAuthenticated(requestContext)) {
throw new ForbiddenException(LocalizationMessages.USER_NOT_AUTHORIZED());
}
for (final String role : rolesAllowed) {
if (requestContext.getSecurityContext().isUserInRole(role)) {
return;
}
}
throw new ForbiddenException(LocalizationMessages.USER_NOT_AUTHORIZED());
}
private static boolean isAuthenticated(final ContainerRequestContext requestContext) {
return requestContext.getSecurityContext().getUserPrincipal() != null;
}
}
它看起来与RolesAllowedRequstFilter 中的代码非常相似。我们正在处理授权,然后将退货委托给另一个Inflector。你会像使用它一样
final String[] rolesAllowed = {"USER"};
methodBuilder.produces(MediaType.TEXT_PLAIN_TYPE)
.handledBy(new AuthorizationInflector(rolesAllowed, new TestInflector()));
唯一真正明显的行为差异(使用变形器而不是过滤器)是使用过滤器,您有顺序优先级的概念。您可以在RolesAllowedRequestFilter 中看到它使用Priorities.AUTHORIZATION 的优先级。它使用它的原因是因为在此过滤器之前发生的身份验证过滤器应该使用优先级Priorities.AUTHENTICATION,这样可以确保在授权之前进行身份验证。
在使用变形器的情况下,您仍然具有此顺序,即身份验证过滤器发生在变形器应用之前。行为的不同之处在于说您要实现其他过滤器,您希望在授权后执行它,因此您可能拥有此
@Priority(Priorities.AUTORIZATION + 100)
class SomeFilter implements ContainerRequestFilter {}
也许您需要对用户进行授权。使用变形器时的问题是直到在这个过滤器之后它才会被调用。这不是您想要的,因为它依赖于已完成的授权。
这是使用变形器进行授权的一个缺点。
我能想到的另一件事可能起作用(虽然我还没有把所有的部分放在一起,就是使用名称绑定。
@NameBinding
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Authorization {}
methodBuilder
.nameBinding(Authorization.class)
.produces(MediaType.TEXT_PLAIN)
.handledBy(new TestInflector());
@Authorization
public class AuthorizationFilter implements ContainerRequestFilter {}
您可以像 RolesAllowedRequestFilter 一样实现 AuthorizationFilter。我还没有弄清楚如何从过滤器内部获取允许的角色。您显然不能只将它传递给过滤器,因为它需要根据资源方法进行限定。我不确定这是否可以完成。这是我需要进一步玩的东西。
目前,我能想到的唯一经过测试和工作的就是使用变形器。