Как я могу извлечь переменную, зависящую от контекста, в класс из метода, чтобы избежать дублирования кода? - PullRequest
0 голосов
/ 28 октября 2019

У меня есть два класса.

Основным классом является распознаватель запросов GraphQL:

@Component
@AllArgsConstructor
class UserProfileQuery implements GraphQLQueryResolver {

    private final UserProfileRepository userProfileRepository;
    private final AddressRepository addressRepository;
    private final UserRepository userRepository;
    private final UserProfileAccessValidator validator;

    @PreAuthorize("hasAuthority('ACCOUNT_OWNER')")
    public Optional<List<UserProfile>> getUserProfiles(Long accountId) {
        User user = userRepository.findById(LoggedUserHolder.getUserId()).orElseThrow(() -> new NotFoundException(User.class));
        validator.validateAccountOwnerAccess(user, accountId);
        return userProfileRepository.findMatchingAccountId(accountId);
    }

    @PreAuthorize("hasAuthority('ACCOUNT_OWNER')")
    public Optional<UserProfile> getUserProfile(Long userProfileId) {
        User user = userRepository.findById(LoggedUserHolder.getUserId()).orElseThrow(() -> new NotFoundException(User.class));
        User checkedUser = userRepository.findByUserProfileId(userProfileId).orElseThrow(() -> new NotFoundException(User.class));
        validator.validateAccountOwnerAccess(user, checkedUser);
        return userProfileRepository.findById(userProfileId);
    }

    @PreAuthorize("hasAnyAuthority('ACCOUNT_OWNER','USER')")
    public Set<Address> getAddresses(Long userProfileId) {
        User user = userRepository.findById(LoggedUserHolder.getUserId()).orElseThrow(() -> new NotFoundException(User.class));
        User checkedUser = userRepository.findByUserProfileId(userProfileId).orElseThrow(() -> new NotFoundException(User.class));
        validator.validateAccountOwnerAndUserAccess(user, checkedUser);
        return Optional.of(addressRepository.findByUserProfileId(userProfileId)).orElseThrow(() -> new NotFoundException(UserProfile.class));
    }

}

Второй класс является валидатором:

@Component
@AllArgsConstructor
public class UserProfileAccessValidator {

    private final UserRepository userRepository;

    public void validateAccessForUserCreation(CreateUserProfileCommand command) {
        User user = userRepository.findById(LoggedUserHolder.getUserId()).orElseThrow(() -> new NotFoundException(User.class));
        User checkedUser = userRepository.findById(command.getUserId()).orElseThrow(() -> new NotFoundException(User.class));
        validateAccountOwnerAndUserAccess(user, checkedUser);
    }

    public void validateAccountOwnerAndUserAccess(User user, User checkedUser) {
        if (AccessValidationHelper.isAccountOwnerAndHasSameAccount(user, checkedUser)
                || AccessValidationHelper.isUserAndHasSameUserProfileId(user, checkedUser)) {
            throw new IllegalOperationException();
        }
    }

    public void validateAccountOwnerAccess(User user, User checkedUser) {
        if (AccessValidationHelper.isAccountOwnerAndHasSameAccount(user, checkedUser)) {
            throw new IllegalOperationException();
        }
    }

    public void validateAccountOwnerAccess(User user, Long accountId) {
        if (!user.getAccount().getId().equals(accountId)) {
            throw new IllegalOperationException();
        }
    }

}

As Youможно увидеть, что при выборке пользователя происходит много дублирования кода.

    User user = userRepository.findById(LoggedUserHolder.getUserId()).orElseThrow(() -> new NotFoundException(User.class));
    User checkedUser = userRepository.findById(command.getUserId()).orElseThrow(() -> new NotFoundException(User.class));

Как можно реорганизовать оба класса, чтобы избежать этого дублирования кода? Или, по крайней мере, чтобы избежать дублирования:

    User user = userRepository.findById(LoggedUserHolder.getUserId()).orElseThrow(() -> new NotFoundException(User.class));

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

Ответы [ 2 ]

0 голосов
/ 28 октября 2019

Вы должны переместить и общий код в класс Utility (скажем, UserUtility), объявить этот класс как @Component, создать метод, который выполняет желаемую операцию над пользователем, а затем автоматически связать его с вашими двумя классами и использовать его для полученияобщий результат.

Надеюсь, это поможет.

0 голосов
/ 28 октября 2019

Если зарегистрированный пользователь является Принципалом, вы можете использовать выражение @PreAuthorize. Если это работает для вас, вы можете использовать метааннотацию. С помощью метааннотации вы можете уменьшить объем кода. Вот хороший учебник о том, как их использовать: https://www.baeldung.com/spring-security-method-security

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...