我正在尝试使用 Spring Security 注册和登录用户,并为他们提供角色,这是 Spring Security 所需的。目前,我在注册多个用户时收到以下错误。
错误是:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:键“UK_8sewwnpamngi6b1dwaa88askk”的重复条目“USER”
对于许多用户来说,role_name 可以是相同的,因此我为角色创建了一个“id”,它是主键,并且是自动生成的。我的 MySQL 数据库中的“USER_ROLES”表只有一个条目,即第一封电子邮件,以及角色名称“USER”。 Customer 表包含所有条目,无论是否有错误。我会继续努力。
感谢您的浏览。
Customer.java
package com.example.demo.models;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
@Entity
public class Customer implements Serializable {
@NotNull
@Size(min=2, max=25)
private String name;
@GeneratedValue
@Id
private int accountNumber;
private BigDecimal accountFunds;
@NotNull
@Size(min=2)
private String password;
@NotNull
@Size(min=2, max=25)
@Email
private String email;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "USER_ROLES", joinColumns = {
@JoinColumn(name = "CUSTOMER_EMAIL", referencedColumnName = "email")
}, inverseJoinColumns = {
@JoinColumn(name = "ROLE_NAME", referencedColumnName = "name")
})
private List<Role> roles;
public Customer(String name, String password, String email) {
this.name = name;
this.password = password;
this.email = email;
}
public Customer() {}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAccountNumber() {
return accountNumber;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public BigDecimal getAccountFunds() {
return accountFunds;
}
public void setAccountFunds(BigDecimal accountFunds) {
this.accountFunds = accountFunds;
}
}
角色.java
package com.example.demo.models;
import javax.persistence.*;
import java.util.List;
@Entity
public class Role {
@Id
@GeneratedValue
private int id;
private String name;
@ManyToMany(mappedBy = "roles")
private List<Customer> customers;
public Role(String name, List<Customer> customers) {
this.name = name;
this.customers = customers;
}
public Role(String name) {
this.name = name;
}
public Role() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Customer> getCustomers() {
return customers;
}
public void setCustomers(List<Customer> customers) {
this.customers = customers;
}
}
UserService.java
package com.example.demo.models.services;
import com.example.demo.models.Customer;
import com.example.demo.models.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public void createUser(Customer customer) {
Role userRole = new Role("USER");
List<Role> roles = new ArrayList<>();
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
customer.setPassword(encoder.encode(customer.getPassword()));
roles.add(userRole);
customer.setRoles(roles);
userRepository.save(customer);
}
public void createAdmin(Customer customer) {
Role userRole = new Role("ADMIN");
List<Role> roles = new ArrayList<>();
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
customer.setPassword(encoder.encode(customer.getPassword()));
roles.add(userRole);
customer.setRoles(roles);
userRepository.save(customer);
}
}
用户存储库
package com.example.demo.models.services;
import com.example.demo.models.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<Customer, String> {
}
安全配置
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
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;
import javax.sql.DataSource;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select email as principal, password as credentials, true from customer where email=?")
.authoritiesByUsernameQuery("select customer_email as principal, role_name as role from user_roles where customer_email=?")
.passwordEncoder(passwordEncoder()).rolePrefix("ROLE_");
}
@Override
protected void configure(HttpSecurity http) throws Exception{
http
.csrf().disable()
.authorizeRequests()
.antMatchers(
"/**/webjars/**",
"/cheese/signup",
"/cheese/login",
"/cheese/success").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/cheese/login")
.defaultSuccessUrl("/cheese/account")
.permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
最佳答案
好的,我已经开始工作了。 SecurityConfig 是相同的,只是您需要将 'role_name' 更改为 'role_id'。
为了给出一点解释,我做了以下操作:
- 将 ID 添加到角色,使其成为主键/自动生成。
- 对于客户多对多,我将客户电子邮件连接到(反向连接)角色“id”
- 对于角色,我做了一对多映射。将角色“id”与(反向连接)客户电子邮件连接起来。
代码...
Customer.java
package com.example.demo.models;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
@Entity
public class Customer implements Serializable {
@NotNull
@Size(min = 2, max = 25)
private String name;
@GeneratedValue
@Id
private int accountNumber;
private BigDecimal accountFunds;
@NotNull
@Size(min = 2)
private String password;
@NotNull
@Size(min = 2, max = 25)
@Email
private String email;
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name="user_roles",
joinColumns={@JoinColumn(name="CUSTOMER_EMAIL", referencedColumnName = "email")},
inverseJoinColumns={@JoinColumn(name="ROLE_ID", referencedColumnName="id")})
private List<Role> roles;
public Customer(String name, String password, String email) {
this.name = name;
this.password = password;
this.email = email;
}
public Customer() {}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAccountNumber() {
return accountNumber;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public BigDecimal getAccountFunds() {
return accountFunds;
}
public void setAccountFunds(BigDecimal accountFunds) {
this.accountFunds = accountFunds;
}
}
角色.java
package com.example.demo.models;
import javax.persistence.*;
import java.util.List;
@Entity
public class Role {
@Id
@GeneratedValue
private int id;
private String name;
@OneToMany(cascade=CascadeType.ALL)
@JoinTable(name="user_roles",
joinColumns={@JoinColumn(name="ROLE_ID", referencedColumnName="id")},
inverseJoinColumns={@JoinColumn(name = "CUSTOMER_EMAIL", referencedColumnName = "email")
})
private List<Customer> customers;
public Role(String name, List<Customer> customers) {
this.name = name;
this.customers = customers;
}
public Role(String name) {
this.name = name;
}
public Role() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Customer> getCustomers() {
return customers;
}
public void setCustomers(List<Customer> customers) {
this.customers = customers;
}
}
关于mysql - Spring 安全: Getting MySQL duplicate entry error when registering more than one user,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50533314/