Jersey客户端使用经过身份验证的会话

时间:2015-07-22 14:45:47

标签: java jersey jax-rs

在给定的时刻,会创建一个经过身份验证的会话。

我需要使用经过身份验证的会话创建一个泽西客户端(post方法)。

我已尝试在jersey客户端中设置JSESSIONID,但它无法识别会话。

    Client client = Client.create();

    final String url = "http://localhost:8080/api/send";

    WebResource wr = client.resource(url);

    javax.ws.rs.core.Cookie cookie=new javax.ws.rs.core.Cookie("JSESSIONID", "521448844J5WE54D");
    wr.cookie(cookie);

    // Set POST parameters
    FormDataMultiPart multipart = new FormDataMultiPart();
    FormDataBodyPart fdp = new FormDataBodyPart("file", uploadedInputStream, MediaType.MULTIPART_FORM_DATA_TYPE);
    multipart.bodyPart(fdp);

    String response = wr.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(String.class, multipart);

    System.out.println(response);

我也试过下面的代码,在jersey客户端我首先调用一个API来验证会话,然后尝试使用相同的客户端对象来调用另一个需要auth会话的API,但是没有用。

    Client client = Client.create();

    final String url = "http://localhost:8080/api/auth";

    WebResource wr = client.resource(url);

     //set parametes for request
    MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
    queryParams.add("user", "admin");
    queryParams.add("pass", "123456");
    wr.queryParams(queryParams);

    ClientResponse response = wr.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(ClientResponse.class);

    System.out.println(response.getCookies().toString());

    //------------------------------------------------------------

    final String url2 = "http://localhost:8080/api/send";

    WebResource wr2 = client.resource(url2);

    // Set POST parameters
    FormDataMultiPart multipart = new FormDataMultiPart();

    FormDataBodyPart fdp = new FormDataBodyPart("file", uploadedInputStream, MediaType.MULTIPART_FORM_DATA_TYPE);
    multipart.bodyPart(fdp);

    String response2 = wr2.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(String.class, multipart);

    System.out.println(response2);

我该怎么做?我的意思是,如何在新的泽西客户端连接中使用经过身份验证的JSESSIONID?

问候。

1 个答案:

答案 0 :(得分:0)

我认为最好的方法是使用JWT进行用户授权。

我假设您已经通过API端点对用户进行了身份验证。用户通过身份验证后,您可以回复标头元素。您可以阅读有关JWT @ https://jwt.io/introduction/

的更多信息

您的实施应如下所示。

1)验证用户,验证成功后,在响应中添加“Authorization:”令牌。

2)在每次API调用中,期望用户为每个请求传递Authorization标头,并使用Filter通过解析JWT令牌来授权用户。您可能想要@Inject the Parser并确保您的解析器是Threadsafe。

3-a)如果JWT令牌有效,您可以将请求传递给您的资源。

3-b)如果JWT令牌无效,请回复HTTP 401。

以下是一个示例实现。

import com.google.inject.Inject;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.proc.BadJOSEException;
import com.nimbusds.jose.proc.SecurityContext;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.JWTParser;
import com.nimbusds.jwt.proc.ConfigurableJWTProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Priority;
import javax.ws.rs.Priorities;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.text.ParseException;


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

 static JWTParser jwtParser = null;

 private static final Logger LOGGER = LoggerFactory.getLogger(SimpleAuthorizationFilter.class);

 @Inject
 private ConfigurableJWTProcessor jwtProcessor;

 public SimpleAuthorizationFilter() {
  LOGGER.debug("Init {}", getClass().getName());
 }

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

  if (LOGGER.isDebugEnabled()) {
   LOGGER.debug("Began authorization filter for {}", requestContext.getUriInfo().getPath());
  }

  MultivaluedMap < String, String > headers = requestContext.getHeaders();

  JWT jwt = null;

  if (headers.containsKey(AccessTokens.AUTHORIZATION)) {

   String accessToken = headers.getFirst(AccessTokens.AUTHORIZATION);


   try {
    jwt = JWTParser.parse(accessToken);
   } catch (ParseException parseException) {
    LOGGER.error("Unable to parse JWT Token {}, reason {}", requestContext.getUriInfo().getPath(), parseException.getMessage());
    throw new WebApplicationException("Unable to parse JWT Token", Response.Status.UNAUTHORIZED);

   }


   // Check if JWT has been init successfully.
   if (jwt == null) {
    LOGGER.error("JWT is null {}", requestContext.getUriInfo().getPath());
    throw new WebApplicationException("Unable to init JWT", Response.Status.UNAUTHORIZED);
   }


   try {

    if (jwt.getJWTClaimsSet().getExpirationTime().before(new java.util.Date())) {
     LOGGER.debug("JWT Token expired on {}, requesting new token ", jwt.getJWTClaimsSet().getExpirationTime().toString());

    } else {
     // Do nothing, continue as usual.
    }

   } catch (ParseException e) {
    LOGGER.error("Authorization failed @ {} , due to {}", requestContext.getUriInfo().getPath(), e.getMessage());
    throw new WebApplicationException("Unable to Authorize " + e.getMessage(), Response.Status.UNAUTHORIZED);
   }


   SecurityContext ctx = null; // optional context parameter, not required here

   JWTClaimsSet claimsSet = null;


   try {
    claimsSet = jwtProcessor.process(accessToken, ctx);
   } catch (ParseException e) {
    LOGGER.error("Authorization failed @ ParseException {} , due to {}", requestContext.getUriInfo().getPath(), e.getMessage());
    throw new WebApplicationException("Unable to Authorize " + e.getMessage(), Response.Status.UNAUTHORIZED);
   } catch (BadJOSEException e) {
    LOGGER.error("Authorization failed @ BadJOSEException {} , due to {}", requestContext.getUriInfo().getPath(), e.getMessage());
    throw new WebApplicationException("Unable to Authorize " + e.getMessage(), Response.Status.UNAUTHORIZED);
   } catch (JOSEException e) {
    LOGGER.error("Authorization failed @ JOSEException {} , due to {}", requestContext.getUriInfo().getPath(), e.getMessage());
    throw new WebApplicationException("Unable to Authorize " + e.getMessage(), Response.Status.UNAUTHORIZED);
   }


   // This should not have happened.
   if (claimsSet == null) {
    LOGGER.error("JWT Claim is null failed @ {} , due to {}", requestContext.getUriInfo().getPath());
    throw new WebApplicationException("Unable to Authorize", Response.Status.UNAUTHORIZED);
   }

  } else {
   LOGGER.error("Authorization header is missing {}", requestContext.getUriInfo().getPath());
   throw new WebApplicationException("Authorization header is missing", Response.Status.UNAUTHORIZED);
  }


 }

}

我实际上创建了一个注释@Secured,并且首先使用此过滤器打开使用@Secured注释的任何资源方法。

这是我的注释:

import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Secured { }

然后我创建了一个DynamicFeature:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;

@Provider
public class ResourceFilterBindingFeature implements DynamicFeature {

    private static final Logger LOGGER = LoggerFactory.getLogger(ResourceFilterBindingFeature.class);

    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext context) {
        if (resourceInfo.getResourceMethod().isAnnotationPresent(Secured.class)) {
            LOGGER.info("{} is annotated to be a secure method " , resourceInfo.getResourceMethod().getName() );
            context.register(CustomAuthorizationFilter.class);
        }

    }
}

您需要在泽西岛注册上述DyamicFeature

register(SimpleAuthorizationFilter.class)

最后,这是我用来测试的资源

import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;


@Path("/authorizationTest")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public class AuthorizationTest {

    @GET
    @Path("/secure")
    @Secured
    public Response secure(){

        return Response.ok(MediaType.APPLICATION_JSON).build();
    }

    @GET
    @Path("/unsecure")
    public Response unsecure(){
        return Response.ok(MediaType.APPLICATION_JSON).build();

    }

}

希望有所帮助。