我正在尝试在dropwizard中添加自定义授权但无法成功。
我通过将其绑定到authFactory
为dropwizard添加了自定义身份验证Authenticator ssoAuthenticator = createSSOAuthenticator(configuration.getSsoGrantClientConfiguration());
environment.jersey().register(AuthFactory.binder(
new SSOTokenAuthFactory<SSOGrant>(
ssoAuthenticator,
SYSTEM_PREFIX,
SSOGrant.class))
);
并添加动态功能以进行授权
environment.jersey().register(PermissionDynamicFeature.class);
以下是创建的注释
@Documented
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER,java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD})
public @interface PermissionsAllowed {
String[] value();
}
我正在检查方法上是否存在注释,然后注册过滤器
public class PermissionDynamicFeature implements DynamicFeature {
@Override
public void configure(final ResourceInfo resourceInfo, final FeatureContext configuration) {
final AnnotatedMethod am = new AnnotatedMethod(resourceInfo.getResourceMethod());
final Annotation[][] parameterAnnotations = am.getParameterAnnotations();
for (Annotation[] annotations : parameterAnnotations) {
for (Annotation annotation : annotations) {
if (annotation instanceof PermissionsAllowed) {
configuration.register(new RolesAllowedRequestFilter(((PermissionsAllowed)annotation).value()));
return;
}
}
}
}
//@Priority(Priorities.USER) // authorization filter - should go after any authentication filters
private static class RolesAllowedRequestFilter implements ContainerRequestFilter {
private final boolean denyAll;
private final String[] rolesAllowed;
RolesAllowedRequestFilter() {
this.denyAll = true;
this.rolesAllowed = null;
}
RolesAllowedRequestFilter(final String[] rolesAllowed) {
this.denyAll = false;
this.rolesAllowed = (rolesAllowed != null) ? rolesAllowed : new String[] {};
}
@Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
if (!denyAll) {
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;
}
}
}
我只是想根据与RolesAllowed过滤器相同的行来构建我的授权。
我面临的问题是在身份验证之前调用了Authorization过滤器。 我缺少什么,以便首先进行身份验证,稍后调用授权过滤器?
当我们注册RolesAllowedDynamicFeature
时会发生同样的情况environment.jersey().register(RolesAllowedDynamicFeature.class);
甚至在身份验证发生之前就会调用RolesAllowedDynamicFeature。
答案 0 :(得分:0)
所以基于你的答案,我写了一个测试,我相信我可以告诉你这里的问题是什么。
您用于提供身份验证令牌的Authfactory不是请求过滤器。根据泽西的文档,这是请求的执行顺序:
https://jersey.java.net/documentation/latest/filters-and-interceptors.html#d0e9976
问题如下:
在执行绑定之前,将始终执行所有请求过滤器。在请求时,球衣甚至不知道它是否需要将任何东西绑定到你的方法上。为什么要创建任何东西,过滤器可能会在请求执行之前拒绝该请求。
简而言之,使用@Auth注释您的资源方法只需在您的泽西环境中添加注入活页夹。您可以在此处阅读自定义注入:
https://jersey.java.net/documentation/latest/ioc.html
这显然是正常的,非常方便,但不是你想要的。 你想要的是在它通过任何过滤器之前拒绝一个请求。为此你必须写一个请求过滤器。用正确的优先级注释它,一切都应该正常工作。
您可以考虑将auth逻辑提取到公共类(您已经做过),然后使用RequestFilter和Authenticator注册相同的类,从而保留Auth提供程序,同时仍然基于Authentication进行请求筛选
JTextField
添加缓存,您不必担心两次调用相同的内容。
我相信dropwizard并不打算使用过滤器。看来他们的目的是将auth上下文注入资源方法并在那里进行身份验证等。不是我首选的解决方案,但它可以工作。
总结一下:
开箱即用的dropwizard不支持您想要做的事情。解决方案是将其解决方案扩展到请求过滤器。
希望有所帮助,
阿图尔