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