Ant*_*s42 5 java jax-rs httprequest cdi
我有这样的网络服务:
@Path("/projects")
public class Projects {
[...]
@Inject
CurrentRequest current;
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
public Response getProject(@PathParam("id") String id) {
if (current.isUserAuthenticated()) {
[...do something...]
} else {
[...produce an error...]
}
}
}
Run Code Online (Sandbox Code Playgroud)
还有一个带有auth checker方法的CDI bean,如下所示:
@RequestScoped
public class CurrentRequest {
public boolean isUserAuthenticated() {
[...do some header checking...]
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,我不能为我的生活从内部抓住HTTP标头CurrentRequest.我试过注射HttpServletRequest,但它没有初始化.我试过用@Context同样的东西.显然FacesContext.getCurrentInstance()不起作用,因为没有FacesContext.
我看到这个问题基本上是在问同样的问题,但是没有得到太多的关注.
我目前的方法是使用@Context HttpServletRequest request内部Projects并将其作为参数传递给current.isUserAuthenticated(request).但那感觉很糟糕.CDI bean不应该知道它自己的请求吗?
我错过了什么?
您不需要HttpServletRequest在JAX-RS端点中从请求中获取HTTP标头.相反,你可以注入HttpHeaders:
@Context
HttpHeaders httpHeaders;
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用HttpHeadersAPI来获取标头值:
HttpHeaders#getHeaderString(String)HttpHeaders#getRequestHeaders()HttpHeaders#getHeaderString(String)如果需要标准HTTP标头的值,请考虑使用API中提供HttpHeaders的常量:
// Get the value of the Authorization header
String authorizationHeader = httpHeaders.getHeaderString(HttpHeaders.AUTHORIZATION);
Run Code Online (Sandbox Code Playgroud)
由于您正在执行身份验证和/或授权,因此我建议您使用过滤器,这样您就可以保持REST端点的精简并专注于业务逻辑.
要将过滤器绑定到REST端点,JAX-RS提供元注释@NameBinding,可以使用如下:
@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Secured { }
Run Code Online (Sandbox Code Playgroud)
该@Secured注释将被用来装饰一个过滤器类,它实现ContainerRequestFilter,让您处理请求.
它ContainerRequestContext可以帮助您从HTTP请求中提取信息(有关更多详细信息,请查看ContainerRequestContextAPI):
@Secured
@Provider
@Priority(Priorities.AUTHENTICATION)
public class SecurityFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Use the ContainerRequestContext to extract information from the HTTP request
// Information such as the URI, headers and HTTP entity are available
}
}
Run Code Online (Sandbox Code Playgroud)
ContainerRequestFilter#filter()如果用户未经过身份验证/授权,则该方法是中止请求的好地方.为此,您可以使用ContainerRequestContext#abortWith()或抛出异常.
该@Provider注释标记的扩展接口期间提供扫描阶段,应该是由JAX-RS运行时发现的实现.
要将过滤器绑定到端点方法或类,请使用@Secured上面创建的注释对其进行 注释.对于注释的方法和/或类,将执行过滤器.
@Path("/")
public class MyEndpoint {
@GET
@Path("{id}")
@Produces("application/json")
public Response myUnsecuredMethod(@PathParam("id") Long id) {
// This method is not annotated with @Secured
// The security filter won't be executed before invoking this method
...
}
@DELETE
@Secured
@Path("{id}")
@Produces("application/json")
public Response mySecuredMethod(@PathParam("id") Long id) {
// This method is annotated with @Secured
// The security filter will be executed before invoking this method
...
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,安全过滤器将仅执行,mySecuredMethod(Long)因为它带有注释@Secured.
您可以根据需要为REST端点提供尽可能多的过滤器.要确保过滤器的执行顺序,请使用@Priority.
强烈建议使用Priorities类中定义的值之一(将使用以下顺序):
如果您的过滤器未注释@Priority,则将以USER优先级执行过滤器.
你可能会发现这个答案很有用.