Я разрабатываю Backend Service, используя JAX-RS и JWT для аутентификации. Но с JWT, когда пользователь входит в систему на новых устройствах, будет сгенерирован новый токен JWT, а предыдущий токен JWT для этого пользователя будет недействительным. Итак, как я могу использовать сеанс или что-то в этом роде, чтобы запомнить логин пользователя на всех устройствах, которые у него есть?
Вот мой код для входа и проверки аутентификации:
@POST
@Path("/authenticate")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response authenticateCredentials(@HeaderParam("email") String email,
@HeaderParam("password") String password, @HeaderParam("accessToken") String accessToken,
@HeaderParam("type") String loginType)
throws JsonGenerationException, JsonMappingException, IOException {
logger.info("Authenticating User Credentials...loginType : " + loginType);
StatusMessage<Users> statusMessage = null;
String jweSerialization = null;
if (loginType == null){
statusMessage = new StatusMessage();
statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
statusMessage.setMessage("login type value is missing...");
return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
}
LoginType type = LoginType.valueOf(loginType);
switch (type) {
case systems:
if (email == null){
statusMessage = new StatusMessage();
statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
statusMessage.setMessage("email value is missing...");
return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
}
if (password == null){
statusMessage = new StatusMessage();
statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
statusMessage.setMessage("password value is missing...");
return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
}
Users user = usersDAO.validate(email, password);
logger.info("user after validate : " + user);
if (user == null){
statusMessage = new StatusMessage();
statusMessage.setStatus(Status.NOT_FOUND.getStatusCode());
statusMessage.setMessage("User not found...");
return Response.status(Status.NOT_FOUND.getStatusCode()).entity(statusMessage).build();
}
jweSerialization = getJWEToken(user);
user.setPassword(null); //not return password and OTP
user.setOTP(null);
statusMessage = new StatusMessage<Users>();
statusMessage.setStatus(Status.OK.getStatusCode());
statusMessage.setMessage(jweSerialization);
statusMessage.setData(user);
logger.info("statusMessage : " + statusMessage);
return Response.status(Status.OK.getStatusCode()).entity(statusMessage).build();
case facebook:
if (email == null){
statusMessage = new StatusMessage<Users>();
statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
statusMessage.setMessage("email value is missing...");
return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
}
if (accessToken == null){
statusMessage = new StatusMessage<Users>();
statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
statusMessage.setMessage("facebook access token value is missing...");
return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
}
FacebookAuth facebookAuth = new FacebookAuth();
SocialUser fbUser = facebookAuth.verifySocialUser(accessToken);
if (fbUser == null){
statusMessage = new StatusMessage<Users>();
statusMessage.setStatus(Status.FORBIDDEN.getStatusCode());
statusMessage.setMessage("Fail while verify facebook user...");
return Response.status(Status.FORBIDDEN.getStatusCode()).entity(statusMessage).build();
}
Users fb_user = usersDAO.validate(fbUser.getEmail(), null);
if (fb_user == null){
statusMessage = new StatusMessage<Users>();
statusMessage.setStatus(Status.NOT_FOUND.getStatusCode());
statusMessage.setMessage("User not found...");
return Response.status(Status.NOT_FOUND.getStatusCode()).entity(statusMessage).build();
}
jweSerialization = getJWEToken(fb_user);
fb_user.setPassword(null); //not return password and OTP
fb_user.setOTP(null);
statusMessage = new StatusMessage<Users>();
statusMessage.setStatus(Status.OK.getStatusCode());
statusMessage.setMessage(jweSerialization);
statusMessage.setData(fb_user);
logger.info("statusMessage : " + statusMessage);
return Response.status(Status.OK.getStatusCode()).entity(statusMessage).build();
case google:
if (email == null){
statusMessage = new StatusMessage<Users>();
statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
statusMessage.setMessage("email value is missing...");
return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
}
if (accessToken == null){
statusMessage = new StatusMessage<Users>();
statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
statusMessage.setMessage("google access token value is missing...");
return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
}
GoogleAuth googleAuth = new GoogleAuth();
SocialUser ggUser = googleAuth.verifySocialUser(accessToken);
if (ggUser == null){
statusMessage = new StatusMessage<Users>();
statusMessage.setStatus(Status.FORBIDDEN.getStatusCode());
statusMessage.setMessage("Fail while verify Goolge user...");
return Response.status(Status.FORBIDDEN.getStatusCode()).entity(statusMessage).build();
}
Users gg_User = usersDAO.validate(ggUser.getEmail(), null);
if (gg_User == null){
statusMessage = new StatusMessage<Users>();
statusMessage.setStatus(Status.NOT_FOUND.getStatusCode());
statusMessage.setMessage("User not found...");
return Response.status(Status.NOT_FOUND.getStatusCode()).entity(statusMessage).build();
}
jweSerialization = getJWEToken(gg_User);
gg_User.setPassword(null); //not return password and OTP
gg_User.setOTP(null);
statusMessage = new StatusMessage<Users>();
statusMessage.setStatus(Status.OK.getStatusCode());
statusMessage.setMessage(jweSerialization);
statusMessage.setData(gg_User);
logger.info("statusMessage : " + statusMessage);
return Response.status(Status.OK.getStatusCode()).entity(statusMessage).build();
default:
statusMessage = new StatusMessage<Users>();
statusMessage.setStatus(Status.FORBIDDEN.getStatusCode());
statusMessage.setMessage("Wrong login type...");
return Response.status(Status.FORBIDDEN.getStatusCode()).entity(statusMessage).build();
}
}




Вы можете получить доступ к ресурсам в JAX-RS, как к сервлету, поскольку JAX-RS фактически построен поверх сервлетов. Итак, да, вы можете получить доступ к сеансу и сохранить информацию о вашем клиенте в сеансах для поддержания состояний (Вот пример).
Однако строго не рекомендуется поддерживать состояния в сеансе веб-служб, как мы это делаем в настройках клиент / сервер. HTTP - это протокол без сохранения состояния, поэтому серверы должны обслуживать каждый запрос изолированно. Стоимость поддержания состояний для каждого из клиентов растет с увеличением количества клиентов и может исчерпать ресурсы вашего сервера. Мы компенсируем эту стоимость в режиме клиент / сервер, чтобы обеспечить лучший пользовательский опыт. Например, сервер может кэшировать часто используемые данные (на основе предыдущих шаблонов запросов) в сеансе, так что время отклика снижается с течением времени за счет минимальных накладных расходов на связь. Напротив, в веб-сервисах серверы фактически обслуживают другие серверы. Таким образом, в этом сценарии компромисс не так полезен, как фактическая настройка клиент / сервер. Потому что для сервера с сервером пропускная способность канала связи не является проблемой. Сервер (действующий как клиент) может предоставить любую необходимую информацию при запросе ресурса на другой сервер.
У вас есть веские основания использовать сеанс. Поскольку вы фактически общаетесь с клиентами, используя JAX-RS, и вам необходимо поддерживать состояния (по крайней мере, для целей аутентификации). Ниже приводится набор рекомендаций, которым вы можете следовать.
После входа в систему с именем пользователя и паролем вы можете предоставить пользователю токен аутентификации и сохранить информацию о пользователе с токеном. Для каждого последующего запроса клиент может отправить токен на сервер, чтобы сервер мог найти идентификатор пользователя. В следующем потоке вы можете увидеть протокол defacto более подробно.
Вы можете рассмотреть возможность использования любого стандартного механизма кэширования (например, JCS, Ehcache, Redis, Memcached и т. д.) Для хранения ваших сеансов, чтобы вы могли в полной мере воспользоваться балансировкой нагрузки экземпляров сервера. Если вы используете сервер приложений JBoss, вам уже доступен Infinispan. Если вы используете сервер Weblogic, вы можете использовать прилагаемый к нему Oracle Coherence. Просто выберите тот, который вам больше всего подходит.
Большое спасибо за ответ, Саззадур. Ваша информация очень-очень полезна для меня. Я буду исследовать, следуя вашему руководству, чтобы найти решение, которое мне подходит. Спасибо