Jax-RS 过滤器将对象传递给资源

Ed_*_*Ed_ 0 java jax-rs

我想将我在过滤器中用于身份验证的用户对象传递给资源。是否可以?

我正在使用wildfly 10(resteasy 3)

@Secured
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {

  @Inject
  private UserDao userDao;

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

    logger.warn("Filter");
    String uid = requestContext.getHeaderString("Authorization");
    User user;
    if((user = validateUser(uid)) == null) {
        requestContext.abortWith(
                Response.status(Response.Status.UNAUTHORIZED).build());
    }
  }

  private User validateUser(String uid) {
    return userDao.getById(uid);
  }
}
Run Code Online (Sandbox Code Playgroud)

std*_*bar 5

我可以看到有两种方法可以做到这一点。第一种可能是更标准的方式,但也是更多的代码。最终,您将作为请求的一部分注入用户。但是,此解决方案首先需要的是Principal。一个非常简单的可能是:

import java.security.Principal;

...

public class UserPrinicipal implements Prinicipal {
  // most of your existing User class but needs to override getName()
}
Run Code Online (Sandbox Code Playgroud)

然后,在您的过滤器中:

...
User user;
if((user = validateUser(uid)) == null) {
    requestContext.abortWith(
            Response.status(Response.Status.UNAUTHORIZED).build());
}

requestContext.setSecurityContext(new SecurityContext() {
    @Override
    public Principal getUserPrincipal() {
        return user;
    }
    @Override
    public boolean isUserInRole(String role) {
        // whatever works here for your environment
    }
    @Override
    public boolean isSecure() {
        return containerRequestContext.getUriInfo().getAbsolutePath().toString().startsWith("https");
    }
    @Override
    public String getAuthenticationScheme() {
        // again, whatever works
    }
});
Run Code Online (Sandbox Code Playgroud)

在您想要用户的类中,您可以执行以下操作:

@Path("/myservice")
public class MyService {
    @Context
    private SecurityContext securityContext;

    @Path("/something")
    @GET
    public Response getSomething() {
        User user = (User)securityContext.getUserPrincipal();
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经以这种方式实现了它,并且效果很好。然而,一种可以说更简单的方法是将用户存储在会话中:

@Context
private HttpServletRequest request;

...

User user;
if((user = validateUser(uid)) == null) {
    requestContext.abortWith(
            Response.status(Response.Status.UNAUTHORIZED).build());
}

request.getSession().setAttribute("user", user);
Run Code Online (Sandbox Code Playgroud)

然后,在您的服务中:

@Path("/myservice")
public class MyService {
    @Context
    private SecurityContext securityContext;

    @Path("/something")
    @GET
    public Response getSomething(@Context HttpServletRequest request) {
        User user = (User)request.getSession().getAttribute("user");
    }
}
Run Code Online (Sandbox Code Playgroud)

第二种方法的缺点是您实际上不再是无状态服务,因为您将状态存储在某处。但是即使您不使用 HttpSession,它也存在。