[英]How to deploy multiple RestEasyInterceptors in a single app?
I am deploying some web services using RestEasy on JBoss 7.1.1. 我正在JBoss 7.1.1上使用RestEasy部署一些Web服务。 I have two classes that process different resource requests along the same path.
我有两个沿着相同路径处理不同资源请求的类。 UserAPI.java handles
/books
and /books/{id}
, etc. MaintenanceAPI.java handles /books/checkedout
. UserAPI.java处理
/books
和/books/{id}
等MaintenanceAPI.java手柄/books/checkedout
。
UserAPI requires a previous login, which is validated by a RestEasyInterceptor called AuthInterceptor
. UserAPI需要先前的登录,该登录由名为
AuthInterceptor
验证。 The maintenance API does not require a login, but should only be accessible as a GET via localhost; 维护API不需要登录,而只能通过localhost作为GET访问; it's handled by
LocalInterceptor
. 由
LocalInterceptor
处理。
To keep them separate, AuthInterceptor's accept() method returns false if declaring.getName().contains("Maintenance")
- so it should not process /books/checkedout
at all. 为了使它们分开,如果
declaring.getName().contains("Maintenance")
.getName declaring.getName().contains("Maintenance")
,则AuthInterceptor的accept()方法返回false,因此它根本不应该处理/books/checkedout
。 LocalInterceptor's accept() method returns true if declaring.equals(MaintenanceAPI.class)
. 如果是
declaring.equals(MaintenanceAPI.class)
则LocalInterceptor的accept()方法将返回true。
AuthInterceptor is declared in web.xml under 'resteasy.providers'. AuthInterceptor在web.xml中的“ resteasy.providers”下声明。 But Eclipse thinks there can be only 1 parameter in the XML element, so LocalInterceptor has the annotation
@Provider
in hopes it'll magically work. 但是Eclipse认为XML元素中只能有1个参数,因此LocalInterceptor具有注释
@Provider
,希望它可以神奇地起作用。
Rejected XML config 拒绝XML配置
This fails: 这将失败:
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>com.foo.AuthInterceptor</param-value>
<param-value>com.foo.LocalInterceptor</param-value>
</context-param>
I'm not sure what the correct syntax is, there is no help in the RestEasy docs. 我不确定正确的语法是什么,RestEasy文档没有帮助。 This also fails:
这也会失败:
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>com.foo.AuthInterceptor</param-value>
</context-param>
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>com.foo.LocalInterceptor</param-value>
</context-param>
However, what's happening is that a URL request from a remote machine to /books/checkedout
( which should fail with NOT_AUTHORIZED ) is routed to the UserAPI's /books/{id}/
handler, which proceeds to try to deal with it and returns a very big exception!! 但是,正在发生的事情是,从远程计算机到
/books/checkedout
checkedout的URL请求( 应该以NOT_AUTHORIZED失败 )被路由到UserAPI的/books/{id}/
处理程序,该处理程序尝试处理该请求并返回一个非常大的例外!! That's wrong for several reasons: it's not the right path, not the right handler, not the right argument type, and it should require an auth token! 这有几个原因,这是错误的:它不是正确的路径,不是正确的处理程序,不是正确的参数类型,并且它需要一个auth令牌! Apparently, LocalInterceptor is not magically added via the annotation, so it's not getting a chance to accept the request.
显然,LocalInterceptor并不是通过注释神奇地添加的,因此它没有机会接受请求。 AuthInterceptor must be correctly rejecting it, but why would UserAPI be asked to handle it and furthermore, why would the
int {id}
be assigned the string "checkedout"? AuthInterceptor必须正确拒绝它,但是为什么要要求UserAPI处理它,而且为什么还要向
int {id}
分配字符串“ checkedout”?
I haven't posted code because I am asking both whether I can even do what I'm trying (like "why can't I subclass String" - no code needed if you understand the question) and why the mapping is trying to do the wrong thing instead of just failing. 我没有发布代码,因为我既问我是否还能做我想做的事情(例如“为什么我不能将String子类化”,如果您理解这个问题就不需要代码),以及为什么要尝试做映射错误的事情而不仅仅是失败。
Maybe it's as simple as getting web.xml correct? 也许就像正确设置web.xml一样简单?
For your XML config ( usually web.xml ), here's what you're looking for. 对于您的XML配置( 通常是web.xml ),这就是您想要的。
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>com.foo.AuthInterceptor, com.foo.LocalInterceptor</param-value>
</context-param>
You should be supplying a comma delimited list of fully qualified @Provider class names. 您应该提供以逗号分隔的完整列表@Provider类名列表。 This will ensure your
LocalInterceptor
also kicks in and does it's job. 这将确保您的
LocalInterceptor
也可以启动并完成工作。 see Table 2.1 of the Documentation . 请参阅文档表2.1 。
That said, I'm assuming your @Path
annotation on both interfaces MaintenanceAPI
and UserAPI
both look like this @Path("/books")
. 就是说,我假设您在接口
MaintenanceAPI
和UserAPI
上的@Path
注释都看起来像这样@Path("/books")
。 This I think is the root of you problems. 我认为这是您问题的根源。
/books/checkedout
is not much different from /books/{id}
at the Interface entry level, until the request hits the handling method so that if a request for /books/checkedout
got into your UserAPI
first (which is expecting /books/{id}
), the string "checkedout"
would be then getting read as the integer {id}
, hence your Very Big Exception... ( i'm guessing it's a NumberFormatException
at the root of the StackTrace ). /books/checkedout
在接口入口级别上与/books/{id}
并没有太大区别,直到请求到达处理方法为止,这样,如果对/books/checkedout
UserAPI
首先进入您的UserAPI
(期望/books/{id}
),然后将字符串"checkedout"
读取为整数{id}
,因此,您的Very Big Exception ...( 我猜这 是StackTrace根目录的 NumberFormatException
)。
In your shoes, I would handle all requests @Path("/books")
with only one interface and change my method paths to NOT conflict with one another. 穿上鞋子,我将仅使用一个接口处理所有
@Path("/books")
请求,并将我的方法路径更改为彼此不冲突。
@Path("/books")
@Produces(MediaType.APPLICATION_JSON)
public interface BooksAPI{
@GET
@Path("/{id}")
public Response getBookByID(@PathParam("id") String id);
// so the url here looks like --> /books/1234
@GET
@Path("/status/checkedout")
public Response getCheckedOut();
// and the url here looks like --> /books/status/checkedout
}
OR if I decide to retain both interfaces, i'll make the entry paths different. 或者,如果我决定保留两个接口,我将使输入路径不同。 Essentially something like these;
本质上是这样的;
@Path("/maintenance")
@Produces(MediaType.APPLICATION_JSON)
public interface MaintenanceAPI{
@GET
@Path("/books/checkedout")
public Response getCheckedOut();
}
// so the url here looks like --> /maintenance/books/checkedout
. 。
@Path("/users")
@Produces(MediaType.APPLICATION_JSON)
public interface UserAPI{
@GET
@Path("/books/{id}")
public Response getBookByID(@PathParam("id") String id);
}
// and the url here looks like --> /users/books/1234
localhost
or remote
, a quite robust technique that i've once used before is access/role management with something like this;
localhost
或remote
请求,我以前曾经使用过的一种非常可靠的技术是使用类似以下内容的访问/角色管理;
Create an Annotation interface like eg 创建一个注释界面,例如
@Documented @Retention (RUNTIME) @Target({TYPE, METHOD}) public @interface RolesAllowed { String[] value(); }
And then your interceptor's accept() method could look like the following; 然后,拦截器的accept()方法可能如下所示;
LocalInterceptor.java LocalInterceptor.java
@Override public boolean accept(Class declaring, Method method) { if(method.isAnnotationPresent(RolesAllowed.class)){ RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class); Set<String> rolesSet = new HashSet<String (Arrays.asList(rolesAnnotation.value())); return rolesSet.contains("local"); } return false; }
AuthInterceptor.java AuthInterceptor.java
@Override public boolean accept(Class declaring, Method method) { if(method.isAnnotationPresent(RolesAllowed.class)){ RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class); Set<String> rolesSet = new HashSet<String (Arrays.asList(rolesAnnotation.value())); return rolesSet.contains("remote"); } return false; }
Finally annotate your interface methods with the desired roles as required. 最后,根据需要为接口方法添加所需的角色。 (NOTE - I'm using the first method that I pointed out above) eg;
(注意-我使用的是我上面指出的第一种方法)
@Path("/books") @Produces(MediaType.APPLICATION_JSON) public interface BooksAPI{ @GET @Path("/{id}") @RolesAllowed({"remote"}) public Response getBookByID(@PathParam("id") String id); @GET @Path("/status/checkedout") @RolesAllowed({"local"}) public Response getCheckedOut(); }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.