我有2个班级: -UserDetailsService -SimpleSocialUserDetailsService 并且我想有两种选择来登录我的应用程序:普通登录/注册并通过Facebook。
我的自定义UserDetailsService看起来如下:
@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);
}
}
SimpleSocialUserDetailsService类的外观如下:
@Service
@RequiredArgsConstructor
public class SimpleSocialUserDetailsService implements SocialUserDetailsService {
private final UserDetailsService userDetailsService;
@Override
public SocialUserDetails loadUserByUserId(String userId)
throws UsernameNotFoundException, DataAccessException {
UserDetails userDetails = userDetailsService.loadUserByUsername(userId);
return new SocialUser(
userDetails.getUsername(),
userDetails.getPassword(),
userDetails.getAuthorities());
}
}
在数据库中,我为普通用户和Facebook用户创建表。对于来自facebook的用户,我具有以下架构:
CREATE TABLE UserConnection (
userId varchar(255) NOT NULL,
providerId varchar(255) NOT NULL,
providerUserId varchar(255),
rank int NOT NULL,
displayName varchar(255),
profileUrl varchar(512),
imageUrl varchar(512),
accessToken varchar(255) NOT NULL,
secret varchar(255),
refreshToken varchar(255),
expireTime bigint,
PRIMARY KEY (userId, providerId, providerUserId));
CREATE UNIQUE INDEX UserConnectionRank
ON UserConnection(userId, providerId, rank);
正常的登录/注册工作正常,我已经在开始时创建了此功能,但是我想通过Facebook获得第二选择。我调试了很多应用程序,问题出在类SimpleSocialUserDetailsService中的这一行:
UserDetails userDetails = userDetailsService.loadUserByUsername(userId);
因为应用无法找到该用户,并且我得到了一个空值,但是在表UserConnection中该用户存在。
我的SocialConfig:
@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;
}
}
我的SecurityConfig:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService userDetailsService;
@Autowired
private DataSource dataSource;
@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);
}
@Bean
public SimpleSocialUserDetailsService simpleSocialUserDetailsService() {
return new SimpleSocialUserDetailsService(userDetailsService);
}
@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());
}
}
针对新用户的我的SecurityImplictConnectionSignUp看起来像这样:
@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;
}
}
我花了一个星期解决这个问题,但仍然无法解决,请提供帮助/提示:) 问候