jax-rs 1.1带有安全过滤器和依赖注入,如何实现呢?

时间:2016-05-30 21:15:40

标签: servlets java-ee jax-rs cdi servlet-filters

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

@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

}

正如您在每个jax-rs方法中看到的,我需要使用相同的代码行:检查令牌将其转换为User对象,< em>如果有效,则返回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
}

因此,如果我达到这一点,我可以确定用户是有效的,我不需要关心它。是否可以通过 JAX-RS 1.1 实现这一目标?

2 个答案:

答案 0 :(得分:4)

我不知道如何在这里完全按照你的意愿行事,但用某些thread local data实现某些事情并不会太难。基本上,过滤器将使用用户信息存储ThreadLocal数据,并且服务方法将能够获取它。这有点像黑客,但它会让你做你想做的事。

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

修改

在考虑了这一点后,为什么不直接使用会话? 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);
        }
    }
}

YourService.java

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

注意&#34;作弊&#34;在这里 - 我们重新注入HttpServletRequest,以便我们可以获得会话以及用户。但是由于过滤器,如果JWT验证失败,则不会调用此方法。

此代码不利用JAX-RS和/或Servlet规范之外的任何内容,应该与app server无关。

答案 1 :(得分:1)

您可以使用过滤器和/或拦截器来实现此目的。这是Jersey示例。

public class AuthorizationRequestFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext)
                    throws IOException {

        final SecurityContext securityContext =
                    requestContext.getSecurityContext();
        if (securityContext == null ||
                    !securityContext.isUserInRole("privileged")) {

                requestContext.abortWith(Response
                    .status(Response.Status.UNAUTHORIZED)
                    .entity("User cannot access the resource.")
                    .build());
        }
    }
}