Внедрение безопасности Spring с аутентификацией AWS congnito на внешнем интерфейсе - PullRequest
1 голос
/ 24 марта 2020

Я делю свое приложение на 2 части:

  • Внешний интерфейс: Vue js и связан с AWS congnito для функции входа в систему (электронная почта / pw или вход в социальную сеть Google).
  • Задняя часть: пружинная загрузка Restful. Информация о пользователе, хранящаяся в базе данных (уникальный идентификатор от congnito в качестве первичного ключа.)

Мой поток аутентификации

  1. Пользователь перенаправлен на congnito и авторизуется. congnito вернет уникальный идентификатор и JWT.
  2. Внешний интерфейс передает уникальный идентификатор и JWT внутреннему контроллеру.
  3. Бэкэнд проверяет JWT и возвращает информацию о пользователе из DB

Мой вопрос:

  • Является ли это плохой практикой для аутентификации на внешнем интерфейсе и передачи данных на сервер для обеспечения безопасности пружины? Если да, могу ли я предложить какие-либо изменения в процессе реализации?
  • Чтобы вызвать AuthenticationProvider.authenticate, необходимо ввести имя пользователя для аутентификации (в моем случае это уникальный идентификатор из cognito) и пароль (UsernamePasswordAuthenticationToken). Есть ли реализация для установки только имени пользователя? или можно установить пароль в виде пустой строки?
// controller
public String login(HttpServletRequest req, String cognitoId, String jwt) { 
    // check JWT with AWS
    if(!AwsJwtChecker(cognitoId, jwt))
        return createErrorResponseJson("invalid jwt");

    UsernamePasswordAuthenticationToken authReq
      = new UsernamePasswordAuthenticationToken(cognitoId, "");
    Authentication auth = authManager.authenticate(authReq);

    SecurityContext sc = SecurityContextHolder.getContext();
    sc.setAuthentication(auth);
    HttpSession session = req.getSession(true);
    session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, sc);

    MyUser user = userRepository.selectUserByCognitoId(cognitoId);
    return createLoginSuccessResponse(user);
}

// web config
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
      String cognitoId = authentication.getName();

      // check user exist in db or not
      MyUser user = userRepository.selectUserByCognitoId(cognitoId);
      if (user != null) {
            return new UsernamePasswordAuthenticationToken(username, "", user.getRoles());
       } else {
            throw new BadCredentialsException("Authentication failed");
       }
    }
    @Override
    public boolean supports(Class<?>aClass) {
        return aClass.equals(UsernamePasswordAuthenticationToken.class);
    }
}

1 Ответ

1 голос
/ 02 апреля 2020

Является ли это плохой практикой для аутентификации на внешнем интерфейсе и передачи данных на сервер для обеспечения безопасности пружины? Если да, могу ли я предложить изменить поток реализации?

Нет, на самом деле это лучшая практика. JWT как раз для этой цели: вы можете хранить информацию о пользователе, и благодаря подписи токена вы можете быть уверены, что информация заслуживает доверия.

Вы не описываете, что вы сохраняете в базы данных, но с моей точки зрения, вы смешиваете два метода аутентификации. Хотя это не запрещено, это может быть ненужным. Вы проанализировали свой токен с jwt.io ? В токене много информации о пользователе, и можно добавить еще.

Cognito ограничен в некотором смысле, например, количеством групп, но для базового c приложения этого может быть достаточно. У него отличный API для управления пользователями из вашего приложения, например, добавление групп или свойств настроек.

Вы не описываете, что вы делаете с информацией, возвращаемой с помощью 3). Vue также может использовать информацию, хранящуюся в jwt, для отображения имени пользователя или чего-то подобного. Вы можете декодировать токен с помощью библиотеки jwt-decode , например, и получить объект со всей информацией.

Для вызова AuthenticationProvider.authenticate ...

Сказав это, я отвечу на ваш второй вопрос: вам не нужна вся аутентификационная часть в вашем login методе.

// controller
public String login(HttpServletRequest req, String cognitoId, String jwt) { 
    // check JWT with AWS
    if(!AwsJwtChecker(cognitoId, jwt))
        return createErrorResponseJson("invalid jwt");

    return userRepository.selectUserByCognitoId(cognitoId);
}

Этого должно быть достаточно, поскольку вы уже проверили токен. Нет необходимости снова аутентифицировать пользователя. Когда весенняя защита настроена правильно, jwt будет автоматически установлен в SecurityContext.

Проблема, которую я вижу с вашей реализацией, заключается в том, что любой может отправить действительный jwt и случайный cognitoId и получить информацию о пользователе из базы данных. , Поэтому было бы лучше проанализировать jwt и использовать что-то из jwt, например имя пользователя, в качестве идентификатора в базе данных. Токеном нельзя манипулировать, иначе проверка не пройдена.

public String login(String jwt) { 
    // check JWT with AWS
    if(!AwsJwtChecker(jwt))
        return createErrorResponseJson("invalid jwt");

    String identifier = getIdentifier(jwt);

    return userRepository.selectUserByIdentifier(identifier);
}
...