【发布时间】:2014-10-08 10:50:46
【问题描述】:
我正在使用 Spring 安全性运行 1.1.4.RELEASE spring-boot 应用程序。我有基本的 Spring 用户和权限表和实体:
@Entity
@Table(name = "USERS")
public class User implements UserDetails {
@Id
private String username;
@Column(nullable = false)
private String password;
private boolean enabled;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
private String companyName;
@OneToMany(mappedBy = "username", fetch = FetchType.EAGER, orphanRemoval = true)
@Cascade({org.hibernate.annotations.CascadeType.ALL})
private Set<Authorities> roles = new HashSet<Authorities>();
/// getters and setters
}
@Entity
public class Authorities {
@Id
private String username;
private String authority;
/// getters and setters
}
我有一个仓库:
public interface UserRepository extends CrudRepository<User, String> {
User findUserByUsername(String username);
void delete(String username);
List<User> findAll();
}
我用作:
@PreAuthorize("hasRole('ADMIN')")
@Transactional
@RequestMapping(value = "/deleteUser/{username}", method = RequestMethod.POST)
public String deleteUser(@PathVariable String username, Model model) {
customUserDetailsService.delete(username);
**the following line throws the exception**
model.addAttribute(UPLOAD, customUserDetailsService.findAllUsers());
return "admin";
}
当我尝试删除用户时,出现错误:
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["IX_AUTH_USERNAME: PUBLIC.AUTHORITIES FOREIGN KEY(USERNAME) REFERENCES PUBLIC.USERS(USERNAME) ('testUser')"; SQL statement:
delete from USERS where username=? [23503-172]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
我认为我的映射是错误的,但老实说我不知道在哪里。
更新: 根据出色的反馈,我现在有以下几点:
@Entity
@Table(name = "USERS")
public class User implements UserDetails {
@Id
private String username;
@Column(nullable = false)
private String password;
private boolean enabled;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
private String companyName;
@ElementCollection(fetch=FetchType.EAGER)
@CollectionTable(name="Authorities", joinColumns=@JoinColumn(name="username"))
@Column(name="authority")
private Set<String> roles = new HashSet<String>();
// getters & setters
}
@Repository
public interface UserRepository extends CrudRepository<User, String> {
User findUserByUsername(String username);
void delete(String username);
List<User> findAll();
}
我通过以下方式使用:
@Controller
@PreAuthorize("hasRole('Admin')")
@RequestMapping("/admin")
public class AdminController {
@PreAuthorize("hasRole('ADMIN')")
@Transactional
@RequestMapping(value = "/deleteUser/{username}", method = RequestMethod.POST)
public String deleteUser(@PathVariable String username, Model model) {
customUserDetailsService.delete(username);
updateModelWithAllUsers(model);
model.addAttribute("user", new User());
return "admin";
}
private void updateModelWithAllUsers(Model model) {
model.addAttribute(USERLIST, customUserDetailsService.findAllUsers());
}
..
}
和
@Component
public class CustomUserDetailsService implements UserDetailsService {
public void delete(String username) {
userRepository.delete(username);
}
..
}
我正在使用 H2,它是我在 liquibase 中创建和播种的:
<createTable tableName="Users">
<column name="username" type="VARCHAR_IGNORECASE(50)"/>
<column name="password" type="VARCHAR_IGNORECASE(500)"/>
<column name="companyName" type="VARCHAR_IGNORECASE(500)"/>
<column name="enabled" type="boolean"/>
<column name="accountNonExpired" type="boolean"/>
<column name="accountNonLocked" type="boolean"/>
<column name="credentialsNonExpired" type="boolean"/>
</createTable>
<createTable tableName="Authorities">
<column name="username" type="VARCHAR(50)">
<constraints primaryKey="true" nullable="false"
foreignKeyName="ix_auth_username" references="Users(username)" deleteCascade="true"/>
</column>
<column name="authority" type="VARCHAR_IGNORECASE(500)"/>
</createTable>
所以这似乎工作正常。边缘条件是,如果我创建一个用户,删除然后创建一个具有相同用户名的用户,我会得到一个异常:
Caused by: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY_KEY_A ON PUBLIC.AUTHORITIES(USERNAME)"; SQL statement:
insert into Authorities (username, authority) values (?, ?) [23505-172]
【问题讨论】:
-
您是否尝试过先删除用户的权限再删除用户?
-
是的,我也试过了,但是它会抛出一个 ReferentialIntegrityException 什么的。
-
要解决问题,请使用
delete的实现以及如何创建表格来更新问题。 -
我已经用我当前的代码状态更新了这个问题。有什么想法吗?
-
我对 liquibase 了解不多,但是你好像把主键和外键搞混了。权限表的主键必须跨越用户名和权限。否则,一个用户只能拥有一个角色。
标签: spring-security spring-data-jpa spring-boot