Spring Security + JPA用户架构

时间:2013-05-07 08:42:28

标签: spring hibernate jpa spring-mvc spring-security

根据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 个答案:

答案 0 :(得分:2)

当使用默认JdbcDaoImpl作为UserDetailsService实现时,您只需坚持Spring安全参考文档中给出的模式,如果您有<jdbc-user-service>标记,就是这种情况你的安全配置。即使这样,也可以覆盖用于获取用户和权限的默认SQL查询(请参阅namespace appendix)。

但是,如果您使用hibernate管理用户帐户,则编写自己的UserDetailsService实现是有意义的,而不是尝试创建导致JdbcDaoImpl所需的特定架构的JPA实体。 / p>

documentation州:

  

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

答案 1 :(得分:1)

有几种方法可以解决这个问题:

要使用您感兴趣的方法,您必须知道除了字段用户名,密码和启用的spring安全性之外,用户名必须是唯一标识符。这意味着您可以将实体的username属性用作数据库和Hibernate的Id。   如果你不想这样做,那么接近这个就是设置一个表,用一个ID / Name和权限来定义授权。然后设置使用jointable将它们映射到用户。   一些未经测试的示例代码: 的作用:

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

当基地运行时,您可以添加内部使用的属性。

答案 2 :(得分:0)

我已经找出了“配置JdbcUserDetailsManager以使用自定义SQL查询”的替代方案,至少我可以通过JPA创建我的表并且可以希望 “user-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 :(得分: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;
    }

}