我正在使用resteasy-jaxrs-3.0.9.FINAL.
我有两个单独的javax.ws.rs.core.Applications
@ApplicationPath("oauth")
public class OAuthApplication extends Application {
final Set<Class<?>> classes = new HashSet<>();
@Nonnull
@Override
public Set<Class<?>> getClasses() {
classes.add(RegisterResource.class);
classes.add(TokenResource.class);
classes.add(HelloResource.class);
return Collections.unmodifiableSet(classes);
}
}
用于基于/ oauth的端点,以及
@ApplicationPath("rest")
public class RestApplication extends Application {
final Set<Class<?>> classes = new HashSet<>();
@Nonnull
@Override
public Set<Class<?>> getClasses() {
classes.add(CategoryResource.class);
classes.add(CategoryGroupResource.class);
classes.add(TransactionResource.class);
classes.add(MonthlySummaryResource.class);
classes.add(MemberResource.class);
return Collections.unmodifiableSet(classes);
}
}
我的筛选器看起来像
@Provider
public class CorsFeature implements Feature {
@Override
public boolean configure(FeatureContext featureContext) {
CorsFilter corsFilter = new CorsFilter();
corsFilter.getAllowedOrigins().add("*");
corsFilter.setAllowedMethods("OPTIONS, GET, POST, DELETE, PUT, PATCH");
featureContext.register(corsFilter);
return true;
}
}
我还将过滤器应用于我的/ rest / *资源,如下所示:
@WebFilter("/rest/*")
public class AuthTokenValidatorFilter implements Filter {
private static final String BEARER_HEADER = "BEARER";
private static final String COLON = ":";
private static final Pattern PATTERN = Pattern.compile(COLON);
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
final HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
if (httpRequest.getHeader(BEARER_HEADER) == null || !isValidAuthToken(httpRequest.getHeader(BEARER_HEADER))) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
private static boolean isValidAuthToken(@Nonnull final String header) {
final String[] tokenParts = PATTERN.split(header);
if (tokenParts.length != 3) {
// hash, uuid, timestamp
return false;
}
final int nanoTimeStamp;
try {
nanoTimeStamp = Integer.parseInt(tokenParts[2]);
} catch (final NumberFormatException e) {
return false;
}
final String hashedAuthToken = new UniqueIdGenerator().getHashedAuthToken(tokenParts[1], nanoTimeStamp);
return hashedAuthToken.equals(tokenParts[0]);
}
@Override
public void destroy() {
}
}
当我启动应用程序并点击端点时,我看到
~ curl -v http://localhost:9090/application/oauth/hello
* Trying ::1...
* Connected to localhost (::1) port 9090 (#0)
> GET /application/oauth/hello HTTP/1.1
> Host: localhost:9090
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< X-Powered-By: Undertow 1
< Server: Wildfly 8
< Content-Type: application/octet-stream
< Content-Length: 5
< Date: Fri, 26 May 2017 19:05:15 GMT
<
* Connection #0 to host localhost left intact
hello%
我看不到返回的CORS标头.
我在这里想念什么?
解决方法:
我/您猜想您的代码是从this post开始的.此问与答的要点是OP希望能够继续使用类路径扫描,即保持
@ApplicationPath("/api")
public class RestApplication extends Application {
}
当您有一个空的Application类时,它将触发对用@Path和@Provider注释的类的类路径扫描.所有这些类都将自动注册.但是,一旦在Application类中重写getClasses()或getSingletons()并在其中一个中返回非空集,则将自动禁用类路径扫描.
因此,OP试图找出如何在不禁用类路径扫描的情况下注册CorsFilter.解决方案是使用带有@Provider注释的功能. @Provider允许自动发现和注册功能.
在您的情况下,您禁用了类路径扫描功能.因此,您只需要注册Feature或由于不使用类路径扫描,就可以忘记Feature,而直接在Application类中注册CorsFilter
@Override
public Set<Object> getSingletons() {
Set<Object> providers = new HashSet<>();
CorsFilter corsFilter = new CorsFilter();
corsFilter.getAllowedOrigins().add("*");
corsFilter.setAllowedMethods("OPTIONS, GET, POST, DELETE, PUT, PATCH");
providers.add(corsFilter);
return providers;
}
顺便说一句,即使您已正确注册过滤器,您的cURL请求也不会显示CORS标头.期望在请求上看到一个Origin标头.
更新
另外,您需要考虑有关servlet过滤器和JAX-RS应用程序的调用顺序. Servlet过滤器在JAX-RS之前调用.这涉及到JAX-RS级别的CORS支持.
因此,将发生的事情是,当客户端发出预检(CORS)请求时,将调用servlet过滤器.请注意,这只是一个预检请求,因此不会发送任何标头,包括令牌标头.预检只是检查服务器是否允许该请求.该预检发生在实际请求之前.这就是CORS协议的工作方式.
因此,在预检中,该响应应包含CORS响应标头,但是对于您的Servlet过滤器,它不会发送此响应.您仅发送未经授权的回复.因此,CORS将永远无法工作.
几个解决方案是:
>在Servlet过滤器级别设置CORS支持.您将无法使用RESTEasy CorsFilter.您只需要自己实施即可.
>您可以使用JAX-RS ContainerRequestFilter,而不是在servlet过滤器中进行身份验证.这样,身份验证和CORS支持就处于同一级别.
如果您选择第二种方法,基本上您会做类似
if (notAuthenticated()) {
requestContext.abortWith(Response.status(401).build()));
return;
}