Spring Security + JPA 用户模式
Posted
技术标签:
【中文标题】Spring Security + JPA 用户模式【英文标题】:Spring Security + JPA user schema 【发布时间】:2013-05-01 03:44:12 【问题描述】:根据 Spring 文档,如果您需要通过数据库管理 Spring 安全性,您应该有一些标准的表模式。例如。
create table users(
username varchar(256) not null primary key,
password varchar(256) not null,
enabled boolean not null
);
create table authorities (
username varchar(256) not null,
authority varchar(256) not null,
constraint fk_authorities_users foreign key(username) references users(username)
);
create unique index ix_auth_username on authorities (username,authority);
我面临的问题如下。 1) 无法理解如何使用 JPA 实现这种表模式?
我尝试了以下方法。
@Entity
@Table(name="USERS")
public class UsersPersistence extends Users implements Serializable
private static final long serialVersionUID = 1009548075747154488L;
public UsersPersistence()
super();
public UsersPersistence(long id, String userName, String password, boolean enabled)
super(id, userName,password,enabled);
@Id
@GeneratedValue
@Column(name="id")
@Override
public long getId()
return super.getId();
@Column(name="username", nullable=false)
@Override
public String getUserName()
return super.getUserName();
@Column(name="password", nullable=false)
@Override
public String getPassword()
return super.getPassword();
@Column(name="enabled", nullable=false)
@Override
public boolean isEnabled()
return super.isEnabled();
此表根据 Spring 文档架构中所述的要求创建。 理解的问题是当我试图在权限表中的用户名上分配外键时。由于 JPA 通过父表(主键表)的 id 分配外键,或者我可能不知道如何分配它。
以下是产生问题的 JPA 类:-
@Entity
@Table(name="AUTHORITIES")
public class AuthoritiesPersistence extends Authorities implements Serializable
private static final long serialVersionUID = 1L;
public AuthoritiesPersistence()
super();
public AuthoritiesPersistence(long id, UsersPersistence userName, String authority)
super(id,userName,authority);
@Id
@GeneratedValue
@Column(name="id")
@Override
public long getId()
return super.getId();
@Override
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="username", nullable=false)
public UsersPersistence getUserName()
return (UsersPersistence) super.getUserName();
@Column(name="authority", nullable=false)
@Override
public String getAuthority()
return super.getAuthority();
此表创建成功,但 Spring 安全认证无法识别用户名,因为 JPA 使用外键 id 而不是实际用户名。
任何帮助都将不胜感激。我真的被困在创建一个基于用户名而不是 id 的外键。 谢谢
【问题讨论】:
您的表中没有指定 id。 首先感谢您的快速回复@Kelvin。两个表中都指定了 ID。两个持久性类都扩展了一些父类。这些类有 id 并且在持久性类中我只是覆盖那些 getter 并将它们分配为 table id 列。 但是 ddl 没有提到 id 列 绝对正确。 DDL 没有提到 id 列。那就是问题所在。如果没有 id,我如何分配外键。 JPA 中是否可以根据 DDL 分配这样的外键?或者我没有其他选择,只能手动创建表模式并使用 JDBC dao 而不是 JPA Dao 类? 【参考方案1】:当您使用默认的JdbcDaoImpl
作为UserDetailsService
实现时,您只需遵守Spring Security 参考文档中给出的架构,如果您的安全配置中有<jdbc-user-service>
标记,就是这种情况。即使这样,也可以覆盖用于获取用户和权限的默认 SQL 查询(请参阅namespace appendix)。
但是,如果您使用 hibernate 管理用户帐户,编写自己的 UserDetailsService
实现而不是尝试创建导致 JdbcDaoImpl
所需的特定架构的 JPA 实体是有意义的。
documentation 也表示:
如果您的应用程序确实使用 ORM 工具,您可能更愿意编写自定义 UserDetailsService 来重用您可能已经创建的映射文件。
【讨论】:
感谢您的回复@zagyi。根据规范,您不能更改架构。问题从来不在于规范所说的内容。问题是有什么可能的方法可以通过 JPA 实现该模式。 我的意思是说,在你的情况下,忘记使用<jdbc-user-service>
可能更容易,它是默认模式。使用 hibernate 实现您自己的 UserDetailsService
几乎是微不足道的,在任何情况下都不会将其视为 hack 或实现身份验证的非标准方式。【参考方案2】:
我已经找到了替代方案,即“配置 JdbcUserDetailsManager 以使用自定义 SQL 查询”至少我可以通过 JPA 创建我的表并且可以希望 “ users-by-username-query 和 authority-by-username-query ”确实可以完成我的工作。 为了实现它,我必须添加以下架构。
create table custom_user_authorities (
id bigint identity,
user bigint not null,
authority varchar(256) not null,
);
此架构有 id(将自动递增),它肯定适用于 JPA。
【讨论】:
【参考方案3】:有几种方法可以解决这个问题:
您可以使用 Hibernate 编写自己的 AuthenticationProvider 数据库访问 您可以使用<jdbc-user-service>
并覆盖@zagyi 提到的SQL 查询。 (http://static.springsource.org/spring-security/site/docs/current/reference/appendix-namespace.html#nsa-jdbc-user-service)
或者您可以创建适合标准<jdbc-user-service>
的架构
要使用您感兴趣的方法,您必须知道,除了拥有用户名、密码和启用的 Spring Security 字段之外,还希望用户名是唯一标识符。这意味着您可以使用实体的用户名属性作为数据库和 Hibernate 的 ID。 如果您不想这样做,一种解决方法是设置一个表,其中使用 ID/名称和权限定义权限。然后设置使用可连接将它们映射到用户。 一些未经测试的示例代码: 角色:
@Entity
@DynamicUpdate
@Table(name ="authorities")
public class Authority
private String authority;
@Id
@Column(name="authority")
public String getAuthority()
return authority;
用户:
@Entity
@DynamicUpdate
@Table(name = "users", uniqueConstraints= @UniqueConstraint(columnNames="username"))
public class User
private String username;
private List<Authority> authorities;
@Type(type = "numeric_boolean")
private boolean enabled;
@Id
@Column(name="username")
public String getUsername()
return username;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "authorities",
joinColumns = @JoinColumn(name = "username"),
inverseJoinColumns = @JoinColumn(name = "rolename")
)
public List<Authority> getauthorities()
return authorities;
@Column(name="ENABLED")
public boolean isEnabled()
return enabled;
当基础运行时,您可以根据需要添加内部使用的属性。
【讨论】:
【参考方案4】:我能够使用以下类定义映射这些表:
@Entity
@Table(name = "users")
public class User
@Id
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@Column
private boolean enabled;
@Column
private String firstName;
@ElementCollection
@JoinTable(name = "authorities", joinColumns = @JoinColumn(name = "email"))
@Column(name = "authority")
private Set<String> roles;
public User()
public Serializable getId()
return username;
public String getUsername()
return username;
public String getPassword()
return password;
public boolean isEnabled()
return enabled;
public void setEnabled(boolean enabled)
this.enabled = enabled;
public void setPassword(String password)
this.password = password;
public void setUsername(String username)
this.username = username;
public String getPassword()
return password;
public void setPassword(String password)
this.password = password;
public Set<String> getRoles()
return roles;
public void setRoles(Set<String> roles)
this.roles = roles;
【讨论】:
以上是关于Spring Security + JPA 用户模式的主要内容,如果未能解决你的问题,请参考以下文章
使用spring boot、jpa和security的多用户restful api
Spring、Spring Security、JPA、MySQL、Hibernate 配置
Spring Security 3.1 + JPA - 空指针异常
Spring Security 3 身份验证与 Hibernate 3(JPA) 注释的集成
具有 Security EvaluationContextExtensionSupport 的 Spring Data JPA 不起作用