jax-rs 1.1 具有安全过滤器和依赖项注入,如何实现这一点?

Ana*_*oly 4 servlets jax-rs cdi servlet-filters jakarta-ee

例如,我有以下JAX-RS 1.1方法,该方法接收JWT 令牌,检查它,然后处理或拒绝请求,如下所示:

@GET
public Response getBook(@HeaderParam("Authorization") String authorizationToken, @QueryParam("id") String bookId) {

    //if(authorizationToken is a valid JWT token)
    //      get User object which represented by this token
    //      get required book from database
    //      return 200 code with a book within response
    //else if(authorizationToken is invalid by whatever reason it's)
    //      return 401 code within a response
    //else if(database error)
    //      return 500 code within a response

}
Run Code Online (Sandbox Code Playgroud)

正如您在每个 jax-rs 方法中看到的,我需要使用相同的代码行:检查 token将其转换为Userobject如果无效则返回 401 错误

实际上,我可以通过在静态方法中提取它来优化它,该方法将执行此检查并User在成功时返回对象,或者Exception在出现问题时抛出异常。我还可以创建webfilter,它会在到达 jax-rs 方法之前检查标头并验证令牌,如果令牌无效,则会以 401 异常中止它。

但我想共同实现这一切。Webfilter这将验证 JWT 令牌,如果它有效,则将其转换User对象并将其注入jax-rs 方法中,如下所示:

@GET
public Response getBook(@RequestByUser User user, @QueryParam("id") String bookId) {

    //if(get required book from database was successfull)
    //      return 200 code with a book within response
    //else(database error)
    //      return 500 code within a response
}
Run Code Online (Sandbox Code Playgroud)

因此,如果我达到了这一点,我可以确定 User 是有效的,我不需要关心它。使用JAX-RS 1.1可以实现这一点吗?

std*_*bar 5

我不知道有什么方法可以准确地完成您想要的操作,但是使用一些线程本地数据来实现某些东西并不会太难。基本上,过滤器将存储带有用户信息的 ThreadLocal 数据,并且服务方法将能够获取它。这有点麻烦,但它可以让你做你想做的事。

但要小心 - 线程本地数据与线程一起存在 - 尽量不要在其中存储巨大的对象,否则如果您有大量客户端,您可能会遇到内存问题。

编辑

想了一下,为什么不直接使用session呢?ThreadLocal 假设过滤器和服务在同一线程上运行。这可能是真的,但不能保证。

所以在你的过滤器中:

JWTFilter.java

@WebFilter(urlPatterns={"/*"}
public class JWTFilter implements Filter {
        public void doFilter(ServletRequest request,
                             ServletResponse response,
                             FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;

        String jwt = req.getHeader("Authorization");
        User user = getUserFromJWT(jwt);  // you'll have to code this
        if(user != null) {
            req.getSession().setAttribute("user", user);
            chain.doFilter(request, response);
        }
        else {
            HttpServletResponse resp = (HttpServletResponse)response;
            resp.sendError(HttpServletResponse.SC_FORBIDDEN);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

你的服务.java

@GET
public Response getBook(@QueryParam("id") String bookId,
                        @Context HttpServletRequest request) {
    User user = (User)request.getSession().getAttribute("user");    
}
Run Code Online (Sandbox Code Playgroud)

注意这里的“作弊”——我们注入 HttpServletRequest,以便我们可以获得会话以及用户。但由于过滤器的原因,如果 JWT 验证失败,则不会调用此方法。

此代码不利用 JAX-RS 和/或 Servlet 规范之外的任何内容,并且应该与应用程序服务器无关。