例如,我有以下 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 实现这一目标?
答案 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());
}
}
}