[英]Spring Security - Repository SocialUser
My problem is to get log in my web application with facebook. 我的问题是使用Facebook登录我的Web应用程序。 Normal login/register works fine but when it comes by social provider i have a problem, below are my importants files along others: 正常的登录/注册工作正常,但是当社交提供程序出现问题时,以下是我的重要文件:
SecurityConfig.java SecurityConfig.java
package pl.java.learning.todolist.infrastructure.config;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService userDetailsService;
@Autowired
private DataSource dataSource;
@Autowired
private UserSocialService userSocialService;
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.withDefaultSchema();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder(11);
}
@Override
protected MyUserDetailsService userDetailsService() {
return userDetailsService;
}
@Bean
public SimpleSocialUserDetailsService simpleSocialUserDetailsService() {
return new SimpleSocialUserDetailsService(userDetailsService, userSocialService);
}
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf().disable()
.headers().frameOptions().disable()
.and()
.authorizeRequests()
.antMatchers("/login*", "/success*").anonymous()
.antMatchers("/auth/**", "/signup/**", "/css/*", "/webjars/**","/js/*","/image/*").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login")
.successForwardUrl("/tasks")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/logout-success").permitAll()
.and()
.apply(new SpringSocialConfigurer());
}
}
SocialConfig.java SocialConfig.java
package pl.java.learning.todolist.infrastructure.config;
@Configuration
@EnableSocial
public class SocialConfig implements SocialConfigurer {
@Autowired
private DataSource dataSource;
@Bean
public ConnectController connectController(
ConnectionFactoryLocator connectionFactoryLocator,
ConnectionRepository connectionRepository) {
return new ConnectController(connectionFactoryLocator, connectionRepository);
}
@Override
public void addConnectionFactories(ConnectionFactoryConfigurer connectionFactoryConfigurer,
Environment env) {
connectionFactoryConfigurer.addConnectionFactory(new FacebookConnectionFactory(
env.getProperty("spring.social.facebook.app-id"),
env.getProperty("spring.social.facebook.app-secret")
));
}
@Override
public UserIdSource getUserIdSource() {
return new AuthenticationNameUserIdSource();
}
@Override
public UsersConnectionRepository getUsersConnectionRepository(
ConnectionFactoryLocator connectionFactoryLocator) {
JdbcUsersConnectionRepository repository =
new JdbcUsersConnectionRepository(
dataSource,
connectionFactoryLocator,
Encryptors.noOpText());
repository.setConnectionSignUp(
new SecurityImplicitConnectionSignUp(userDetailsManager()));
return repository;
}
@Bean
public JdbcUserDetailsManager userDetailsManager() {
JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
manager.setDataSource(dataSource);
manager.setEnableAuthorities(true);
return manager;
}
}
CustomSocialUser.java CustomSocialUser.java
package pl.java.learning.todolist.domain.social;
import java.util.Collection;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.security.core.GrantedAuthority;
import pl.java.learning.todolist.infrastructure.persistence.BaseEntity;
@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString
@Table(name = "users")
public class CustomSocialUser extends BaseEntity {
private String username;
private String password;
private Collection<? extends GrantedAuthority> authorities;
}
SimpleSocialUserDetailsService.java SimpleSocialUserDetailsService.java
@Service
@RequiredArgsConstructor
public class SimpleSocialUserDetailsService implements SocialUserDetailsService {
private final UserDetailsService userDetailsService;
private final UserSocialService userSocialService;
@Override
public SocialUserDetails loadUserByUserId(String userId)
throws UsernameNotFoundException, DataAccessException {
CustomSocialUser customSocialUser = userSocialService.findByUsername(userId);
return new SocialUser(
customSocialUser.getUsername(),
customSocialUser.getPassword(),
customSocialUser.getAuthorities());
}
}
MyUserDetailsService.java MyUserDetailsService.java
@Service
@RequiredArgsConstructor
public class MyUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByLogin(username);
if(user == null) {
throw new UsernameNotFoundException(username);
}
return new MyUserPrincipal(user);
}
}
SecurityImplicitConnectionSignUp.java SecurityImplicitConnectionSignUp.java
@RequiredArgsConstructor
public class SecurityImplicitConnectionSignUp implements ConnectionSignUp {
public final UserDetailsManager userDetailsManager;
@Override
public String execute(Connection<?> connection) {
String providerUserId = connection.getKey().getProviderUserId();
User newUser = new User(providerUserId,
"",
Arrays.asList(new SimpleGrantedAuthority("USER")));
userDetailsManager.createUser(newUser);
return providerUserId;
}
}
UserSocialRepository.java UserSocialRepository.java
public interface UserSocialRepository extends JpaRepository<CustomSocialUser, Long> {
@Query("SELECT u FROM Users u WHERE u.username = ?1")
CustomSocialUser findByUsername(String username);
}
MyUserPrincipal.java MyUserPrincipal.java
@RequiredArgsConstructor
public class MyUserPrincipal implements UserDetails {
private final User user;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getRoles();
}
public Long getUserId() {
return user.getId();
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getLogin();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return user.getEnabled();
}
}
I got error like this: 我有这样的错误:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not determine type for: java.util.Collection, at table: users, for columns: [org.hibernate.mapping.Column(authorities)]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1699)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:573)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1089)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:859)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:762)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:398)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:330)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1258)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246)
at pl.java.learning.todolist.TodoListApplication.main(TodoListApplication.java:10)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not determine type for: java.util.Collection, at table: users, for columns: [org.hibernate.mapping.Column(authorities)]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:402)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1758)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1695)
... 21 common frames omitted
Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Collection, at table: users, for columns: [org.hibernate.mapping.Column(authorities)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:456)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:423)
at org.hibernate.mapping.Property.isValid(Property.java:226)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:597)
at org.hibernate.mapping.RootClass.validate(RootClass.java:265)
at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:329)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:461)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:892)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390)
... 25 common frames omitted
The problem is in your repository: 问题出在您的存储库中:
@Repository
public interface UserSocialRepository extends JpaRepository<SocialUser, Long> {
@Query("SELECT u FROM Users u WHERE u.username = ?1")
SocialUser findByUsername(String username);
}
1) If you use Spring Data and your class is extended from JpaRepository
, you don't have to add @Repository
annotation on your class. 1)如果使用Spring Data并且您的类是从JpaRepository
扩展的,则不必在类上添加@Repository
批注。
2) In your method 2)用你的方法
SocialUser findByUsername(String username);
you return SocialUser
, which is a class from Spring Social module and this class is not managed by JPA (that's why you receive an error). 您返回SocialUser
,这是Spring Social模块中的一个类,并且该类不受JPA管理(这就是为什么会收到错误)。 You should use either entity or Spring Data projection as a returned type in the method of your repository. 您应该使用实体或Spring Data投影作为存储库方法中的返回类型。
Let's assume that you have Users
entity which should be something like: 假设您具有Users
实体,该实体应类似于:
@Entity
@Table(name = "users")
public class Users {
private String username;
// ...
}
You can rewrite your method in the following way: 您可以通过以下方式重写您的方法:
Users findByUsername(String username);
Then you can convert entity / projection to SocialUser
in your service: 然后,您可以在服务SocialUser
实体/投影转换为SocialUser
:
public UserDetails findByUsername(String username) {
Users user = userSocialRepository.findByUsername(username);
return new SocialUser(user.getUsername(), ...);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.