在给定的时刻,会创建一个经过身份验证的会话。
我需要使用经过身份验证的会话创建一个泽西客户端(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?
问候。
答案 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();
}
}
希望有所帮助。