4

根据 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 的外键。谢谢

4

4 回答 4

3

JdbcDaoImpl当使用默认值作为UserDetailsService实现时,您只需遵守 Spring Security 参考文档中给出的架构,如果您<jdbc-user-service>的安全配置中有标签,就是这种情况。即使这样,也可以覆盖它用于获取用户和权限的默认 SQL 查询(请参阅命名空间附录)。

但是,如果您使用 hibernate 管理用户帐户,则编写自己的UserDetailsService实现是有意义的,而不是尝试创建导致JdbcDaoImpl.

文档还指出:

如果您的应用程序确实使用 ORM 工具,您可能更愿意编写自定义 UserDetailsS​​ervice 来重用您可能已经创建的映射文件。

于 2013-05-07T09:02:32.887 回答
1

有几种方法可以处理这个问题:

要使用您感兴趣的方法,您必须知道除了拥有用户名、密码和启用的 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;
    }

当基础运行时,您可以根据需要添加内部使用的属性。

于 2013-05-21T11:51:20.370 回答
0

我能够使用以下类定义映射这些表:

@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;
    }

}
于 2015-01-27T10:43:59.840 回答
0

我已经找到了替代方案,即“将 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。

于 2013-05-07T09:18:06.730 回答