我正在JBoss 7.1.1上使用RestEasy部署一些Web服务。我有两个类,它们沿同一路径处理不同的资源请求。 UserAPI.java处理/books
和/books/{id}
等.MaingeAPI.java处理/books/checkedout
。
UserAPI需要先前的登录,该登录由名为AuthInterceptor
的RestEasyInterceptor验证。维护API不需要登录,但只能通过localhost作为GET访问;它由LocalInterceptor
处理。
为了使它们分开,AuthInterceptor的accept()方法如果declaring.getName().contains("Maintenance")
则返回false - 所以它根本不应该处理/books/checkedout
。如果declaring.equals(MaintenanceAPI.class)
,则LocalInterceptor的accept()方法返回true。
AuthInterceptor在' resteasy.providers'下的web.xml中声明。但Eclipse认为XML元素中只能有一个参数,因此LocalInterceptor具有注释@Provider
,希望它能够神奇地工作。
拒绝XML配置
这失败了:
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>com.foo.AuthInterceptor</param-value>
<param-value>com.foo.LocalInterceptor</param-value>
</context-param>
我不确定正确的语法是什么,RestEasy文档中没有任何帮助。这也失败了:
<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>
然而,正在发生的事情是,从远程计算机到/books/checkedout
(哪个应该以NOT_AUTHORIZED 失败)的URL请求被路由到UserAPI&#39; { {1}}处理程序,它继续尝试处理它并返回一个非常大的异常!由于以下几个原因,这是错误的:它不是正确的路径,不是正确的处理程序,不是正确的参数类型,它应该需要一个身份验证令牌!显然,LocalInterceptor并没有通过注释神奇地添加,因此它没有机会接受请求。 AuthInterceptor必须正确拒绝它,但为什么要求UserAPI处理它呢?此外,为什么/books/{id}/
会被赋予字符串&#34; checkedout&#34;?
我还没有发布代码,因为我问我是否能做我正在尝试的事情(比如&#34;为什么我可以将String&#34子类化; - 不需要代码如果你理解这个问题)以及为什么映射试图做错事而不是失败。
也许它就像让web.xml正确一样简单?
答案 0 :(得分:0)
对于您的XML配置(通常是web.xml ),这是您正在寻找的内容。
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>com.foo.AuthInterceptor, com.foo.LocalInterceptor</param-value>
</context-param>
您应该提供以逗号分隔的完全限定的@Provider类名列表。这将确保您LocalInterceptor
也开始工作并完成工作。 see Table 2.1 of the Documentation。
也就是说,我假设您在@Path
和MaintenanceAPI
接口上的UserAPI
注释看起来都像@Path("/books")
。我认为这是你问题的根源。
/books/checkedout
与接口条目级别的/books/{id}
差异不大,直到请求到达处理方法,以便/books/checkedout
的请求进入UserAPI
首先(期待/books/{id}
),字符串"checkedout"
将被读作整数{id}
,因此你的非常大的例外...( i&#39; m在StackTrace的根目录下猜测它是 NumberFormatException
。)
在你的鞋子里,我会只用一个界面来处理所有请求@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 如果我决定保留两个接口,我会使输入路径不同。基本上就是这样的东西;
@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
或remote
的请求,我曾经使用的一种非常强大的技术是访问/角色管理,具有类似的功能;
创建一个注释界面,例如
@Documented
@Retention (RUNTIME)
@Target({TYPE, METHOD})
public @interface RolesAllowed {
String[] value();
}
然后你的拦截器的accept()方法可能如下所示;
<强> 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 强>
@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;
}
最后根据需要使用所需的角色注释您的接口方法。 (注意 - 我使用上面提到的第一种方法)例如
@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();
}