无法使用存储在数据库中的凭据登录
Can't login using credentials stored in the database
我创建了一个非常简单的网站,每个人都可以访问/about,经过身份验证的用户可以访问/profile,只有具有“ADMIN”角色的用户才能访问。我在 DBInit.java
中添加了一个“ADMIN”用户,然后我尝试访问 /admin 并获得一个 http 基本登录表单。我输入 adminEmail 作为登录名,输入 admin123 作为密码,但我无法访问 /admin 页面。所以我的代码中某处有错误,我可以看到它。那么错误在哪里以及如何摆脱它呢?
如果我在内存验证中使用一切正常。
// In memory authentication
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
// auth.authenticationProvider(authenticationProvider());
auth.inMemoryAuthentication()
.withUser("admin")
.password(passwordEncoder().encode("admin"))
.roles("ADMIN");
}
SecurityConfiguration.java
import Onlinestore.service.UserPrincipalDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
private UserPrincipalDetailsService userPrincipalDetailsService;
public SecurityConfiguration(UserPrincipalDetailsService userPrincipalDetailsService)
{
this.userPrincipalDetailsService = userPrincipalDetailsService;
}
@Override
protected void configure(AuthenticationManagerBuilder auth)
{
auth.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("/about").permitAll()
.antMatchers("/profile").authenticated()
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.httpBasic();
}
@Bean
DaoAuthenticationProvider authenticationProvider()
{
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(userPrincipalDetailsService);
return daoAuthenticationProvider;
}
@Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
}
User.java
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
@Entity(name = "user")
@Table(name = "users")
@NoArgsConstructor
public class User
{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Getter
@Setter
private int id;
@Getter
@Setter
@Column(nullable = false)
private String name;
@Getter
@Setter
private String surname;
@Getter
@Setter
@Column(nullable = false)
private String password;
@Getter
@Setter
@Column(name = "telephone_number", nullable = false)
private String telephoneNumber;
@Getter
@Setter
@Column(unique = true)
private String email;
@Getter
@Setter
private String country;
@Getter
@Setter
private String address;
@Getter
@Setter
// delimiter = ";"
private String roleNames;
public User(String name, String surname, String password, String telephoneNumber, String email, String country, String address, String roleNames)
{
this.name = name;
this.surname = surname;
this.password = password;
this.telephoneNumber = telephoneNumber;
this.email = email;
this.country = country;
this.address = address;
this.roleNames = roleNames;
}
}
UserPrincipal.java
import Onlinestore.entity.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class UserPrincipal implements UserDetails
{
private User user;
public UserPrincipal(User user)
{
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities()
{
String[] roles = user.getRoleNames().split(";");
List<GrantedAuthority> authorities = new ArrayList<>();
for (String role : roles)
{
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
@Override
public String getPassword()
{
return user.getPassword();
}
@Override
public String getUsername()
{
return user.getName();
}
@Override
public boolean isAccountNonExpired()
{
return false;
}
@Override
public boolean isAccountNonLocked()
{
return false;
}
@Override
public boolean isCredentialsNonExpired()
{
return false;
}
@Override
public boolean isEnabled()
{
return false;
}
}
UserPrincipalDetailsService.java
import Onlinestore.entity.User;
import Onlinestore.repository.UserRepository;
import Onlinestore.security.UserPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class UserPrincipalDetailsService implements UserDetailsService
{
private UserRepository userRepository;
public UserPrincipalDetailsService(UserRepository userRepository)
{
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
User user = userRepository.findUserByEmail(username);
return new UserPrincipal(user);
}
}
DBInit.java
import Onlinestore.entity.User;
import Onlinestore.repository.UserRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
@Service
public class DBInit implements CommandLineRunner
{
private UserRepository userRepository;
private PasswordEncoder passwordEncoder;
public DBInit(UserRepository userRepository, PasswordEncoder passwordEncoder)
{
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
@Override
public void run(String[] args)
{
User user1 = new User("admin", "admin", passwordEncoder.encode("admin123"),
"+111111111", "adminEmail", "country1", "address1", "ADMIN");
List<User> users = Arrays.asList(user1);
userRepository.saveAll(users);
}
}
用户存储库
import Onlinestore.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Integer>
{
User findUserByEmail(String email);
}
内存中身份验证需要配置中的硬编码凭据。它不会从数据库中提取凭据。
如果您想使用数据库中的凭据,您的其余设置乍一看看起来不错。尝试
httpSecurity
.authorizeRequests()
.antMatchers(PUBLIC_MATCHERS)
.permitAll()
.anyRequest()
.authenticated();
其中 PUBLIC_MATCHERS
是一组不需要身份验证的端点,如果您有这样的东西。
我发现了所有错误。
- 在 class
UserPrincipal
中,我不得不覆盖此方法和 return true
,但不是 return false
。我想当我 return false
Spring 安全认为用户被阻止、过期、禁用等并阻止身份验证时。
这但也有一些错误和应用程序尚未按我想要的方式工作。
在 UserPrincipal
中正确实施方法
@Override
public boolean isAccountNonExpired()
{
return true;
}
@Override
public boolean isAccountNonLocked()
{
return true;
}
@Override
public boolean isCredentialsNonExpired()
{
return true;
}
@Override
public boolean isEnabled()
{
return true;
}
- 在 class
UserPrincipal
中,我必须在 getUserName()
中 return user.getEmail()
,但不能 return user.getName()
,因为我使用电子邮件作为身份验证用户名。
@Override
public String getUsername()
{
return user.getEmail();
}
- 在
UserPrincipalDetailsService
class 中 loadUserByUsername()
我不得不抛出异常 UsernameNotFoundException
当没有用户使用这样的用户名时
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
User user = userRepository.findUserByEmail(username);
if (user == null)
{
throw new UsernameNotFoundException("user not found");
}
return new UserPrincipal(user);
}
我创建了一个非常简单的网站,每个人都可以访问/about,经过身份验证的用户可以访问/profile,只有具有“ADMIN”角色的用户才能访问。我在 DBInit.java
中添加了一个“ADMIN”用户,然后我尝试访问 /admin 并获得一个 http 基本登录表单。我输入 adminEmail 作为登录名,输入 admin123 作为密码,但我无法访问 /admin 页面。所以我的代码中某处有错误,我可以看到它。那么错误在哪里以及如何摆脱它呢?
如果我在内存验证中使用一切正常。
// In memory authentication
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
// auth.authenticationProvider(authenticationProvider());
auth.inMemoryAuthentication()
.withUser("admin")
.password(passwordEncoder().encode("admin"))
.roles("ADMIN");
}
SecurityConfiguration.java
import Onlinestore.service.UserPrincipalDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
private UserPrincipalDetailsService userPrincipalDetailsService;
public SecurityConfiguration(UserPrincipalDetailsService userPrincipalDetailsService)
{
this.userPrincipalDetailsService = userPrincipalDetailsService;
}
@Override
protected void configure(AuthenticationManagerBuilder auth)
{
auth.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("/about").permitAll()
.antMatchers("/profile").authenticated()
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.httpBasic();
}
@Bean
DaoAuthenticationProvider authenticationProvider()
{
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(userPrincipalDetailsService);
return daoAuthenticationProvider;
}
@Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
}
User.java
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
@Entity(name = "user")
@Table(name = "users")
@NoArgsConstructor
public class User
{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Getter
@Setter
private int id;
@Getter
@Setter
@Column(nullable = false)
private String name;
@Getter
@Setter
private String surname;
@Getter
@Setter
@Column(nullable = false)
private String password;
@Getter
@Setter
@Column(name = "telephone_number", nullable = false)
private String telephoneNumber;
@Getter
@Setter
@Column(unique = true)
private String email;
@Getter
@Setter
private String country;
@Getter
@Setter
private String address;
@Getter
@Setter
// delimiter = ";"
private String roleNames;
public User(String name, String surname, String password, String telephoneNumber, String email, String country, String address, String roleNames)
{
this.name = name;
this.surname = surname;
this.password = password;
this.telephoneNumber = telephoneNumber;
this.email = email;
this.country = country;
this.address = address;
this.roleNames = roleNames;
}
}
UserPrincipal.java
import Onlinestore.entity.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class UserPrincipal implements UserDetails
{
private User user;
public UserPrincipal(User user)
{
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities()
{
String[] roles = user.getRoleNames().split(";");
List<GrantedAuthority> authorities = new ArrayList<>();
for (String role : roles)
{
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
@Override
public String getPassword()
{
return user.getPassword();
}
@Override
public String getUsername()
{
return user.getName();
}
@Override
public boolean isAccountNonExpired()
{
return false;
}
@Override
public boolean isAccountNonLocked()
{
return false;
}
@Override
public boolean isCredentialsNonExpired()
{
return false;
}
@Override
public boolean isEnabled()
{
return false;
}
}
UserPrincipalDetailsService.java
import Onlinestore.entity.User;
import Onlinestore.repository.UserRepository;
import Onlinestore.security.UserPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class UserPrincipalDetailsService implements UserDetailsService
{
private UserRepository userRepository;
public UserPrincipalDetailsService(UserRepository userRepository)
{
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
User user = userRepository.findUserByEmail(username);
return new UserPrincipal(user);
}
}
DBInit.java
import Onlinestore.entity.User;
import Onlinestore.repository.UserRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
@Service
public class DBInit implements CommandLineRunner
{
private UserRepository userRepository;
private PasswordEncoder passwordEncoder;
public DBInit(UserRepository userRepository, PasswordEncoder passwordEncoder)
{
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
@Override
public void run(String[] args)
{
User user1 = new User("admin", "admin", passwordEncoder.encode("admin123"),
"+111111111", "adminEmail", "country1", "address1", "ADMIN");
List<User> users = Arrays.asList(user1);
userRepository.saveAll(users);
}
}
用户存储库
import Onlinestore.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Integer>
{
User findUserByEmail(String email);
}
内存中身份验证需要配置中的硬编码凭据。它不会从数据库中提取凭据。
如果您想使用数据库中的凭据,您的其余设置乍一看看起来不错。尝试
httpSecurity
.authorizeRequests()
.antMatchers(PUBLIC_MATCHERS)
.permitAll()
.anyRequest()
.authenticated();
其中 PUBLIC_MATCHERS
是一组不需要身份验证的端点,如果您有这样的东西。
我发现了所有错误。
- 在 class
UserPrincipal
中,我不得不覆盖此方法和return true
,但不是return false
。我想当我return false
Spring 安全认为用户被阻止、过期、禁用等并阻止身份验证时。 这但也有一些错误和应用程序尚未按我想要的方式工作。 在UserPrincipal
中正确实施方法
@Override
public boolean isAccountNonExpired()
{
return true;
}
@Override
public boolean isAccountNonLocked()
{
return true;
}
@Override
public boolean isCredentialsNonExpired()
{
return true;
}
@Override
public boolean isEnabled()
{
return true;
}
- 在 class
UserPrincipal
中,我必须在getUserName()
中return user.getEmail()
,但不能return user.getName()
,因为我使用电子邮件作为身份验证用户名。
@Override
public String getUsername()
{
return user.getEmail();
}
- 在
UserPrincipalDetailsService
class 中loadUserByUsername()
我不得不抛出异常UsernameNotFoundException
当没有用户使用这样的用户名时
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
User user = userRepository.findUserByEmail(username);
if (user == null)
{
throw new UsernameNotFoundException("user not found");
}
return new UserPrincipal(user);
}