如何使用Hibernate/JPA2实现Spring Security用户/权限?

Ta *_*Sas 8 java orm hibernate jpa spring-security

我正在尝试实现DAO以在Hibernate/JPA2中使用Spring Security数据库身份验证.Spring使用以下关系和关联来表示用户和角色:

替代文字

作为postgresql创建查询重复:

CREATE TABLE users
(
  username character varying(50) NOT NULL,
  "password" character varying(50) NOT NULL,
  enabled boolean NOT NULL,
  CONSTRAINT users_pkey PRIMARY KEY (username)
);
CREATE TABLE authorities
(
  username character varying(50) NOT NULL,
  authority character varying(50) NOT NULL,
  CONSTRAINT fk_authorities_users FOREIGN KEY (username)
      REFERENCES users (username) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
);
Run Code Online (Sandbox Code Playgroud)

使用板载的实现GrantedAuthorities,UserDetailsService并且UserDetailsmanager,一切都很好.但是,我对Spring的JDBC实现不满意,并且想编写自己的实现.为此,我尝试通过以下业务对象创建关系的表示:

用户实体:

@Entity
@Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = {"username"})})
public class AppUser implements UserDetails, CredentialsContainer {

    private static final long serialVersionUID = -8275492272371421013L;

    @Id
    @Column(name = "username", nullable = false, unique = true)
    private String username;

    @Column(name = "password", nullable = false)
    @NotNull
    private String password;

    @OneToMany(
            fetch = FetchType.EAGER, cascade = CascadeType.ALL,
            mappedBy = "appUser"
    )
    private Set<AppAuthority> appAuthorities;

    @Column(name = "accountNonExpired")
    private Boolean accountNonExpired;

    @Column(name = "accountNonLocked")
    private Boolean accountNonLocked;

    @Column(name = "credentialsNonExpired")
    private Boolean credentialsNonExpired;

    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "personalinformation_fk", nullable = true)
    @JsonIgnore
    private PersonalInformation personalInformation;

    @Column(name = "enabled", nullable = false)
    @NotNull
    private Boolean enabled;

    public AppUser(
            String username,
            String password,
            boolean enabled,
            boolean accountNonExpired,
            boolean credentialsNonExpired,
            boolean accountNonLocked,
            Collection<? extends AppAuthority> authorities,
            PersonalInformation personalInformation
    ) {
        if (((username == null) || "".equals(username)) || (password == null)) {
            throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
        }

        this.username = username;
        this.password = password;
        this.enabled = enabled;
        this.accountNonExpired = accountNonExpired;
        this.credentialsNonExpired = credentialsNonExpired;
        this.accountNonLocked = accountNonLocked;
        this.appAuthorities = Collections.unmodifiableSet(sortAuthorities(authorities));
        this.personalInformation = personalInformation;
    }

    public AppUser() {
    }

    @JsonIgnore
    public PersonalInformation getPersonalInformation() {
        return personalInformation;
    }

    @JsonIgnore
    public void setPersonalInformation(PersonalInformation personalInformation) {
        this.personalInformation = personalInformation;
    }

    // Getters, setters 'n other stuff
Run Code Online (Sandbox Code Playgroud)

而权威实体作为GrantedAuthorities的实现:

@Entity
@Table(name = "authorities", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class AppAuthority implements GrantedAuthority, Serializable {
    //~ Instance fields ================================================================================================

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    @Column(name = "id", nullable = false)
    private Integer id;

    @Column(name = "username", nullable = false)
    private String username;

    @Column(name = "authority", nullable = false)
    private String authority;

    // Here comes the buggy attribute. It is supposed to repesent the
    // association username<->username, but I just don't know how to
    // implement it 
    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "appuser_fk")
    private AppUser appUser;

    //~ Constructors ===================================================================================================

    public AppAuthority(String username, String authority) {
        Assert.hasText(authority,
                "A granted authority textual representation is required");
        this.username = username;
        this.authority = authority;
    }

    public AppAuthority() {
    }

    // Getters 'n setters 'n other stuff
Run Code Online (Sandbox Code Playgroud)

我的问题是@ManyToOne关联.的AppAuthorities:它应该是"用户名",而是试图和这样做将引发一个错误,因为我得典型化属性作为String......而Hibernate所期待的关联实体.所以我尝试的实际上是提供正确的实体并创建关联@JoinColumn(name = "appuser_fk").当然,这是垃圾,因为为了加载用户,我将使用外键username,而Hibernate搜索它时appuser_fk,它将始终为空.

所以这是我的问题:关于如何修改上面提到的代码以获得数据模型的正确JPA2实现的任何建议?

谢谢

axt*_*avt 8

AppAuthority根本不需要username.Spring Security不能依赖它,因为它取决于没有任何方法来访问用户名的GrantedAuthority接口.

但更好的做法是将您的域模型与Spring Security分离.如果有自定义UserDetailsService,则无需模拟Spring Security的默认数据库模式或其对象模型.您UserDetailsService可以加载自己的AppUser,AppAuthority然后根据它们创建UserDetails和创建GrantedAuthority.这导致更清晰的设计,更好地分离关注点.