Java 使用bcrypt的Spring身份验证
我正在尝试将bcrypt添加到我的spring应用程序中。无需验证即可正常工作。但当我尝试使用bcrypt进行编码时,我在尝试登录时会得到“原因:错误的凭据” 我的用户模型如下所示Java 使用bcrypt的Spring身份验证,java,spring,spring-security,Java,Spring,Spring Security,我正在尝试将bcrypt添加到我的spring应用程序中。无需验证即可正常工作。但当我尝试使用bcrypt进行编码时,我在尝试登录时会得到“原因:错误的凭据” 我的用户模型如下所示 @Entity @Table(name="users") // user is a reserved word in postgresql public class User extends BaseEntity { private PasswordEncoder passwordEncoder = new
@Entity
@Table(name="users") // user is a reserved word in postgresql
public class User extends BaseEntity {
private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
...
@Column(nullable=false)
private String password;
...
public String getPassword() {
return password;
}
public void setPassword(String password) {
String hashedPassword = passwordEncoder.encode(password);
this.password = hashedPassword;
}
...
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
private BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
...
}
我的SecurityConfig如下所示
@Entity
@Table(name="users") // user is a reserved word in postgresql
public class User extends BaseEntity {
private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
...
@Column(nullable=false)
private String password;
...
public String getPassword() {
return password;
}
public void setPassword(String password) {
String hashedPassword = passwordEncoder.encode(password);
this.password = hashedPassword;
}
...
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
private BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
...
}
上述情况是否正确?我需要做比我已经做的更多的事情吗?以下是我将如何设置它 用户表有4个属性(除其他属性外)
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
String usrsByUnameQry = "SELECT u.email_address, u.password, u.enabled FROM user u WHERE u.email_address=?";
3String authByUnameQry = "SELECT u.email_address, r.authority FROM user u, role r WHERE u.id=r.user_id AND u.email_address=?";
auth
.eraseCredentials(false)
.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(passwordEncoder())
.usersByUsernameQuery(usrsByUnameQry)
.authoritiesByUsernameQuery(authByUnameQry);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.usernameParameter("username") //username property defined in html form
.passwordParameter("password") //password property defined in html form
// url that holds login form
.loginPage("/signin")
.loginProcessingUrl("/signin/authenticate")
.failureUrl("/loginfail")
// Grant access to users to the login page
.permitAll()
.and()
.logout()
.logoutUrl("/signout")
.deleteCookies("JSESSIONID")
.logoutSuccessUrl("/signin")
.and()
.authorizeRequests()
.antMatchers("/foo/**").permitAll()//Grant access to all (no auth reuired)
.antMatchers("/").hasAnyAuthority("ROLE_USER","ROLE_ADMIN") //Grant access to only users with role "ROLE_USER" or "ROLE_ADMIN"
}
@Bean(name = "authenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public TextEncryptor textEncryptor(){
return Encryptors.noOpText();
}
我的错误在于没有发布足够的代码。当然,我的用户模型并没有说明全部情况。我还有一个名为SecurityUser的类,我在下面发布了这个类。由于复制构造函数的存在,密码会被散列两次
public class SecurityUser extends User implements UserDetails {
private static final long serialVersionUID = 867280338717707274L;
public SecurityUser(User user) {
if(user != null)
{
this.setId(user.getId());
this.setName(user.getName());
this.setEmail(user.getEmail());
this.setPassword(user.getPassword());
this.setRoles(user.getRoles());
}
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
Set<Role> userRoles = this.getRoles();
if(userRoles != null)
{
for (Role role : userRoles) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getName());
authorities.add(authority);
}
}
return authorities;
}
...
}
愚蠢的问题,但您是否检查了数据库中的密码是否经过哈希处理?是的,到目前为止,它看起来是这样的:$2a$10$6k776rYtY.fn8tdfw08ryogfsqdekqqqpocjcovjf/oT/8FQcQ/oyalry已经尝试过了。没有区别。您可以粘贴密码字段的输出吗?$2a$10$jyaYvkHqgBhesyR8WwfQfe07eV/BVTXobwtI6dtxglGQZ0Zq4CYDi-这是以“密码”作为密码的。好的,但是使用此配置,您将对密码编码两次!一次在实体中,一次在用户服务中。如果您的orm使用setter注入属性,您将在另一次对密码进行编码。删除实体的passwordEncoder属性。这毫无意义。如果在不同的服务项目中分离实体(和DAO),则实体中不应包含类
PasswordEncoder
。当然,我将其从模型中删除,仅在服务中包含。谢谢你的输入。好的,用你最新的代码更新你的第一篇文章。添加包含最新更新的编辑节。顺便说一下,我强烈建议您将SecurityUser
和User
分开SecurityUser
不应该扩展User
,而应该实现UserDetails
。否则,您将能够在SecurityUser
上调用UserService.create
方法,或者从另一个方法创建SecurityUser
。这两种情况应该发生,而且,依我看,这种关系是不正确的。删除代码中的这种继承,也许你会发现代码中有什么错误。上面的代码正在运行。我只是在等待,让我接受我自己的答案。因为安全用户不应该包含任何密码。即使它是在欺骗一个用户,它也不是专用于同样的事情。但是,就像我说的,这只是我的错。如果你希望投票给自己的答案,你可以等很长时间!!谢谢你的意见。我选择了一条有点不同的道路。通过实现自定义UserDetailsService类,您可以摆脱安全配置中的sql。