Настройка org.springframework.security.core.userdetails.User для обработки пользовательских свойств пользователя - PullRequest
0 голосов
/ 08 ноября 2018

Каким будет способ настройки org.springframework.security.core.userdetails.User, который обрабатывает аутентификацию на основе enabled, accountNotExpired, credentialsNotExpired и accountNotLocked? Пользователь моего приложения (БД) имеет следующий возможный статус:

PENDING, ACTIVE, DEACTIVATED, BLOCKED, SPAM, DELETED

Я написал кастом UserDetailsService

@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userDao.findByEmail(username)
                .orElseThrow(() -> new UsernameNotFoundException("No account found for " + username));

        return new org.springframework.security.core.userdetails.User(user.getEmail(),
                user.getPassword(),true , true, true, true, getAuthorities("ROLE_USER"));
    }

     private Collection<? extends GrantedAuthority> getAuthorities(String role) {
            return Arrays.asList(new SimpleGrantedAuthority(role));
     }

}

На данный момент я вынужден жестко кодировать true для всех свойств, которые * Spring по умолчанию имеет User. Я хочу свою реализацию этих свойств.

Редактировать: Работа моего пользовательского статуса Accont:
Для spam, delete я хочу, чтобы пользователь решил (в точке входа в систему), хотят ли они восстановить свою учетную запись. Для spam и blocked пользователь сможет получить доступ к домашней странице, но ничего, кроме сообщения, не будет видно. Для deactivated я хочу показать пользователям, что им нужно активировать учетную запись, нажав на ссылку, указанную в полученном им электронном письме.
Как этого добиться? И на каком уровне?

Ответы [ 2 ]

0 голосов
/ 08 ноября 2018

Первое: Расширьте свой класс User с UserDetails и добавьте необходимые поля, такие как имя пользователя, пароль и т. Д.

Секунда: добавьте к ней enabled, accountNotExpired, credentialsNotExpired и accountNotLocked поля и сделайте последние три как transient, так как вы не хотите их сохранять, вы просто используйте их, чтобы проверить, являются ли эти критерии методом или нет.

public enum UserStatus{
    PENDING,
    ACTIVE,
    DEACTIVATED,
    BLOCKED,
    SPAM,
    DELETED
}


public class User implements UserDetails {

    //  ... Other field definitions 
    protected LocalDateTime expireDate;
    protected UserStatus status = UserStatus.ACTIVE;   // load from DB
    @Transient
    protected boolean accountNotExpired = true;

    @Transient
    protected boolean accountNotLocked = false;

    @Transient
    protected boolean credentialsNotExpired = true;

    // ...  getters & setters
}

Реализуйте свой userService, реализуя свои собственные методы из UserService, а также, что более важно, от UserDetailsService до реализовать логику критериев для accountNotExpired, credentialsNotExpired и accountNotLocked.

Здесь я только реализую accountNotExpired, например, вы можете добавить Ваш за credentialsNotExpired и accountNotLocked.

public class UserServiceImpl implements UserService, UserDetailsService {
    private final UserRepository userRepository;

    @Autowired
    public UserServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) {

        User user = userDao.findByEmail(username)
            .orElseThrow(() -> new UsernameNotFoundException("No account found for " + username));

        // check whether you account expired or not
        if ((user.getExpireDate() != null) && (LocalDateTime.now().isAfter(user.getExpireDate()))) {
            user.setAccountNotExpired(false);
        }

        //  Also decide for credentialsNotExpired and accountNotLocked here



        for (Role role: user.getRoles()) {
            for (Permission permission: role.getPermissions()) {
                user.getAuthorities().add(new SimpleGrantedAuthority(permission.getName()));
            }
        }

        return user;
    }
}

Теперь, основываясь на критериях, реализованных на предыдущем шаге, вы Теперь на позиции контроля вашего пользователя путем реализации AuthenticationProvider как:

public class CustomAuthenticationProvider implements AuthenticationProvider {

    private final UserDetailsService userDetailsService;

    @Autowired
    public CustomAuthenticationProvider(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) {
        String username = authentication.getName();
        BCryptPasswordEncoder bcrypt = new BCryptPasswordEncoder();
        String password = (String) authentication.getCredentials();
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        if (userDetails == null) {
            throw new BadCredentialsException("username not found");
        }
        if (!bcrypt.matches(password, userDetails.getPassword())) {
            throw new BadCredentialsException("password incorrect");
        }
        if (!userDetails.isAccountNonExpired()) {
            throw new CredentialsExpiredException("account expired");
        }
        if (!userDetails.isCredentialsNonExpired()) {
            throw new CredentialsExpiredException("password expired");
        }
        if (!userDetails.isAccountNonLocked()) {
            throw new LockedException("account locked");
        }

        // decision point based on user status   
        if (userDetails.getUserStatus() != UserStatus.DEACTIVATED) {
            throw new DisabledException("account deactivated");
        }else if(userDetails.getUserStatus() != UserStatus.PENDING){
                ...
        }else if(userDetails.getUserStatus() != UserStatus.BLOCKED){
                ...
        }else if(userDetails.getUserStatus() != UserStatus.SPAM){
                ...
        }else if(userDetails.getUserStatus() != UserStatus.DELETED){
                ...
        }


        return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
    }

    @Override
    public boolean supports(Class << ? > authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}
0 голосов
/ 08 ноября 2018

Просто вы можете расширить org.springframework.security.core.userdetails.User класс, добавить новые поля и методы (или переопределить существующие, если вам нужно), возможно, это может быть проще, чем создание нового типа пользовательского объекта, который реализует интерфейс UserDetails.

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