Как получить пользовательский объект для пользовательской аутентификации при входе в Spring Security? - PullRequest
0 голосов
/ 10 июля 2019

Я пытаюсь настроить пользовательскую аутентификацию и пользовательскую сущность с помощью Spring Security.Как правильно настроить конфигурацию, чтобы UserRepository мог извлекать информацию о пользователях из базы данных?

Я видел несколько весенних руководств о том, как сделать пользовательский объект для аутентификации и входа в систему, вместо этогоиспользования весенней безопасности по умолчанию.Я не уверен, что проблема заключается в конфигурации безопасности весны или проблема с отображением пользователя и полномочий.Вот конфигурация, контроллер -> UserDetailsService -> Репозиторий, сущности и таблицы sql.

Конфигурация Spring Secutrity

@Configuration
@EnableWebSecurity
@ComponentScan("com.mithrandir.springcrud")
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private AuthenticationSuccessHandlerImpl successHandler;

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(authenticationProvider());
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider
          = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .antMatchers("/").hasRole("USER")
                .antMatchers("/add/**").hasAnyRole("MANAGER", "ADMIN")
                .antMatchers("/updateProduct/**").hasRole("ADMIN")
                .antMatchers("/delete/**").hasRole("ADMIN")
            .and()
            .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/doLogin")
                .successHandler(successHandler)
                .successForwardUrl("/login")
                .usernameParameter("email")
                .passwordParameter("password")
                .permitAll()
            .and()
            .logout()
                .logoutUrl("/doLogout")
                .logoutSuccessUrl("/logout")
                .permitAll()
            .and()  
            .exceptionHandling().accessDeniedPage("/accessDenied");
    }

}

Вход в систему LoginController POST-запрос


    @PostMapping("/login")
    public String postLogin(Model model, HttpSession session) {

        Authentication authentication = SecurityContextHolder
                .getContext().getAuthentication();
        validatePrinciple(authentication.getPrincipal());
        User loggedInUser = ((UserPrincipal) authentication.getPrincipal()).getUser();

        model.addAttribute("currentUserId", loggedInUser.getId());
        model.addAttribute("currentUser", loggedInUser.getEmail());
        session.setAttribute("userId", loggedInUser.getId());
        return "redirect:/";
    }

        private void validatePrinciple(Object principal) {
        if (!(principal instanceof UserPrincipal)) {
            throw new IllegalArgumentException("Principal can not be null!");
        }
    }

AuthenticationSuccessHandler для обновления последней онлайн-даты

@Component
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {

    @Autowired
    UserRepository userRepository;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {
        userRepository.updateLastLogin(new Date());
    }

}

UserDetailsService

@Service
@Transactional
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        User user = userRepository.findByEmail(email);
        System.out.println("UserDetailsService, user from db: " + user);
        if (user == null) {
            throw new UsernameNotFoundException("No user found with email: " + email);
        }
        return new UserPrincipal(user);
    }
}

UserRepository

    @Override 
    public User findByEmail(String email) {
        Session session = sessionFactory.getCurrentSession();

        Query<User> query = session.createQuery("FROM User u WHERE u.email=:email", User.class);
        query.setParameter("email", email);

        System.out.println("UserDAO: finding user by email");
        return query.uniqueResult();
    }

UserPrincipal:

public class UserPrincipal implements UserDetails  {

    /**
     * 
     */
    private static final long serialVersionUID = 777221850757925972L;
    private final User user;

    public UserPrincipal(User user) {
        this.user = user;
    }

    @Override
    public String getUsername() {
        return user.getEmail();
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return user.getAuthorities().stream()
                .map(authority -> new SimpleGrantedAuthority(authority.getAuthority().toString()))
                .collect(Collectors.toSet());
    }
    // getters and setters through the user field
}

Сущность пользователя:


@Entity
@Table(name = "user")
public class User implements Serializable {


    /**
     * 
     */
    private static final long serialVersionUID = 7630269547387051923L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "firstname")
    private String firstName;

    @Column(name = "lastname")
    private String lastName;

    @Column(name = "email", unique = true)
    private String email;

    @Column(name = "password", nullable = false)
    private String password;

    @Column(name = "enabled", nullable = false)
    private boolean enabled;

    @Column(name = "accountNonExpired", nullable = false)
    private boolean accountNonExpired;

    @Column(name = "credentialsNonExpired", nullable = false)
    private boolean credentialsNonExpired;

    @Column(name = "accountNonLocked", nullable = false)
    private boolean accountNonLocked;

    @Column(name = "creationDateTime")
    private Date createDateTime;

    @Column(name = "updatedDateTime")
    private Date updateDateTime;

    @Column(name = "lastOnlineDateTime", nullable = false)
    private Date lastOnline;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinTable(name = "user_authorities",
            joinColumns = { @JoinColumn(name = "user_id") },
            inverseJoinColumns = { @JoinColumn(name = "authority_id") })
    @Fetch(value=FetchMode.SELECT)
    private Set<Authorities> authorities = new HashSet<>();

    public User() {

    }
     //... getters and setters

Сущность полномочий:

@Entity
@Table(name = "authorities")
public class Authorities implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 5383739733021126813L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Enumerated(EnumType.STRING)
    private AuthorityType authority;


    public Authorities(AuthorityType authority) {
        this.authority = authority;
    }
    //... getters and setters

Перечисление AuthorityType:


    public enum AuthorityType {
        ROLE_ADMIN,
        ROLE_MANAGER,
        ROLE_USER
    }

И, наконец, схема sql:

CREATE TABLE `user` (
    `id` BIGINT(19) NOT NULL AUTO_INCREMENT,
    `firstName` VARCHAR(30) NOT NULL,
    `lastName` VARCHAR(30) NOT NULL,
    `email` VARCHAR(50) NOT NULL,
    `password` CHAR(76) NOT NULL,
    `enabled` TINYINT NOT NULL,
    `accountNonExpired` TINYINT NOT NULL,
    `credentialsNonExpired` TINYINT NOT NULL,
    `accountNonLocked` TINYINT NOT NULL,
    `creationDateTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updatedDateTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `lastOnlineDateTime` TIMESTAMP NOT NULL,
    CONSTRAINT user_pk
    PRIMARY KEY (`id`)
);

CREATE TABLE `authorities` (
  `id` BIGINT(19) NOT NULL auto_increment,
  `authority` varchar(50) NOT NULL,
  PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `user_authorities` (
  `user_id` BIGINT(19) NOT NULL,
  `authority_id` BIGINT(19) NOT NULL,
  KEY `user` (`user_id`),
  KEY `authority` (`authority_id`),
  CONSTRAINT `user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `authority` FOREIGN KEY (`authority_id`) REFERENCES `authorities` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Это вывод, который я получаю из консоли при первом вводе правильных учетных данных:

UserDAO: finding user by email
Hibernate: select user0_.id as id1_3_, user0_.accountNonExpired as accountN2_3_, user0_.accountNonLocked as accountN3_3_, user0_.creationDateTime as creation4_3_, user0_.credentialsNonExpired as credenti5_3_, user0_.email as email6_3_, user0_.enabled as enabled7_3_, user0_.firstname as firstnam8_3_, user0_.lastname as lastname9_3_, user0_.lastOnlineDateTime as lastOnl10_3_, user0_.password as passwor11_3_, user0_.updatedDateTime as updated12_3_ from user user0_ where user0_.email=?
Hibernate: select authoritie0_.user_id as user_id1_4_0_, authoritie0_.authority_id as authorit2_4_0_, authoritie1_.id as id1_0_1_, authoritie1_.authority as authorit2_0_1_ from user_authorities authoritie0_ inner join authorities authoritie1_ on authoritie0_.authority_id=authoritie1_.id where authoritie0_.user_id=?
heinäkuuta 10, 2019 5:10:40 IP. org.hibernate.engine.loading.internal.LoadContexts cleanup
WARN: HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@67b156c6<rs=com.mchange.v2.c3p0.impl.NewProxyResultSet@3fe5ce85 [wrapping: null]>
heinäkuuta 10, 2019 5:10:40 IP. org.hibernate.engine.loading.internal.CollectionLoadContext cleanup
WARN: HHH000160: On CollectionLoadContext#cleanup, localLoadingCollectionKeys contained [1] entries

При попытке войти с неверными учетными данными:

UserDAO: finding user by email
Hibernate: select user0_.id as id1_3_, user0_.accountNonExpired as accountN2_3_, user0_.accountNonLocked as accountN3_3_, user0_.creationDateTime as creation4_3_, user0_.credentialsNonExpired as credenti5_3_, user0_.email as email6_3_, user0_.enabled as enabled7_3_, user0_.firstname as firstnam8_3_, user0_.lastname as lastname9_3_, user0_.lastOnlineDateTime as lastOnl10_3_, user0_.password as passwor11_3_, user0_.updatedDateTime as updated12_3_ from user user0_ where user0_.email=?
UserDetailsService, user from db: null

Итак, я вижу, что хранилище может найтипользователь из базы данных, но по какой-то причине не может вытащить его ... Неправильное отображение или конфигурация?Заранее спасибо, что нашли время помочь!

1 Ответ

0 голосов
/ 10 июля 2019

Я установил, что вы хотите, с полной конфигурацией Java без каких-либо XML.

1.) Я думаю, ваша конфигурация безопасности не является правильным.Не используйте аннотацию @ComponentScan, поскольку этот класс не является ни вашим корневым классом конфигурации, ни вашей конфигурацией сервлета.Просто удалите эту строку.

2.) Вы должны указать antmatcher, что делать.Например:

.antMatchers("/administration/**").access("hasRole('ADMIN')")

, потому что вы хотите предоставить доступ к этому URL.

3.) Я не уверен, но вы можете проверить, действительно ли полномочия предоставлены пользователю, еслиучетные данные, где хорошо?Я использую Spring и у меня есть что-то вроде этого в моем UserDetailsService:

if (user != null) {
    Collection<GrantedAuthority> authorites = new ArrayList<GrantedAuthority>();

    for (Iterator<UserUserroles> i = user.getRoles().iterator(); i.hasNext();) {
        UserRole role = i.next().getRoleid();
        authorites.add(new SimpleGrantedAuthority(role.getName()));
    }

    SpringSecurityUser securityUser;
    securityUser = new SpringSecurityUser(user, authorites);
    return securityUser;
} 
throw new UsernameNotFoundException(username);

Я вручную добавляю роли пользователя как Администратора.Возможно, ваше решение разумнее, но проверьте, работает ли эта часть.

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