Best practices for identifying user roles and permissions? - java

What are some best practices when defining users with different roles/permissions, such as normal user with restricted access and administrator with full access?
My user class looks something like this:
#Entity
#Table(name = "users")
public class User {
#Id
#Column(name = "userID")
#GeneratedValue(generator = "increment")
#GenericGenerator(name = "increment", strategy = "increment")
private Long userID;
public Long getUserID() {
return userID;
}
#ManyToOne(fetch = FetchType.LAZY)
#Column(nullable = false)
private Role role;
#Column(nullable = false)
private boolean isActive;
#Column(nullable = false, unique = true)
private String email;
#Column(nullable = false)
private String password;
#Column
#Temporal(TemporalType.TIMESTAMP)
private Calendar lastLoggedIn;
#Column(nullable = false)
#Temporal(TemporalType.TIMESTAMP)
private Calendar createdDate;
#Version
private Integer version;
}
My Role class is:
#Entity
#Table(name = "roles")
public class Role {
#Id
#Column(name = "roleID")
#GeneratedValue(generator = "increment")
#GenericGenerator(name = "increment", strategy = "increment")
private Long roleID;
#Column(nullable = false)
private String roleName;
#Column(nullable = false)
private String rolePermissions;
}
Say my application needed to retrieve a list of user and their roles, should an instance of User hold a reference to an instance (or proxy) of Role? What if my application had to find all Users for a particular Role, does Role have to have a List of Users? What are some tried and true ways of designing and implementing this relationship?
Also, am I doing the mapping correctly with JPA?

You should use,
#CollectionOfElements
#JoinTable(name = "ROLE_PERMISSIONS", joinColumns = #JoinColumn(name = "roleID"))
#Column(name = "Permission")
private List<String> rolePermissions;
instead of,
#Column(nullable = false)
private String rolePermissions;

I would suggest using
#role=Admin
for all the administrator level functions
and use
#role=User
for normal user and more if annotations if necesary

Related

Spring boot JPA related entity clarification

I have an entity like Process, which will be created by , updated by one user. When I try to apply the filter. I have created the foreign key relationship in the database. Now, when I use the JPA Specification to apply dynamic filter, I am getting exception as
No property CREATED found for type Process!
#Table(name = "process")
#Entity
public class Process {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PROCESS_ID")
#JsonProperty("id")
private Long id = null;
#NotNull
#Column(name = "NAME")
#JsonProperty("name")
private String name = null;
#Column(name = "CREATED_BY", updatable = false)
#JsonProperty("createdBy")
private Long createdBy = null;
#Column(name = "updatedBy", nullable = true)
#JsonProperty("updatedBy")
private Long updatedBy = null;
}
Hence, I Added the entity relationship mapping in the process entity as given below,
Now, I am getting below error. I am new to JPA and hibernate, the relation mapping is very confusing, kindly help.
#Table(name = "process")
#Entity
public class Process {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PROCESS_ID")
#JsonProperty("id")
private Long id = null;
#NotNull
#Column(name = "NAME")
#JsonProperty("name")
private String name = null;
#Column(name = "CREATED_BY", updatable = false)
#JsonProperty("createdBy")
private Long createdBy = null;
#Column(name = "updatedBy", nullable = true)
#JsonProperty("updatedBy")
private Long updatedBy = null;
//newly added below properties so that there will be no error when fetching data
#OneToOne(targetEntity = UserDetails.class, fetch = FetchType.LAZY, mappedBy = "id")
private UserDetails CREATED;
#OneToOne(targetEntity = UserDetails.class, fetch = FetchType.LAZY, mappedBy = "id")
private UserDetails UPDATED;
}
Now, I am getting the below error
Referenced property not a (One|Many)ToOne: com.app.users.details.domain.UserDetails.id in mappedBy of com.app.scenarios.domain.Process.CREATED
Kindly let me know what i am doing wrong. I have a process which can be created by a user and can be updated by a user. In DB, I am having a foreign key relationship for process and userdetails entity.
EDIT
Code to get the filtered data from DB using JPA Specification
Page<process> result = this.processDao.findAll(getprocessGridData(processSearchCondition.getprocessName()), pageRequest);
private static Specification<process> getprocessGridData(String processName) {
return (Specification<process>) (root, query, criteriaBuilder) -> (
criteriaBuilder.like(root.get("name"), processName)
);
}
I guess what you actually want is this:
#Table(name = "process")
#Entity
public class Process {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PROCESS_ID")
#JsonProperty("id")
private Long id;
#NotNull
#Column(name = "NAME")
#JsonProperty("name")
private String name;
#OneToOne(fetch = FetchType.LAZY)
#jOINColumn(name = "CREATED_BY", updatable = false)
private UserDetails createdBy;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "UPDATED_BY", nullable = true)
private UserDetails updatedBy;
}

Spring Data JPA/Hibernate LazyInitializationException

I am new to hibernate/spring data JPA and occuring some problems when dealing with Foreign Keys.
I have the two table:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private String email;
#Column(nullable = false)
private String password;
#Column(nullable = false)
private String role;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "job_id", referencedColumnName = "id")
private Job job;
}
#Entity
public class Job{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String name;
#OneToMany(
mappedBy = "job",
cascade = CascadeType.PERSIST,
fetch = FetchType.EAGER
)
private Set<User> users = new HashSet<>();
}
I am trying to save one Job (job.Id) at the Users table. But if I am trying to peform a get(repository.getOne(id)) (via ...extends JPARepository<User,Long> I am getting the following error:
org.hibernate.LazyInitializationException: could not initialize proxy [backend.entity.User#193] - no Session
Does anyone has a Tip how to fix it? I have read a lot on stackoverflow, but could not find out how to fix that.

mapping multiple collection with one entity

I have a four entity class as listed bellow.
the mapping requirement is like-
1-Customer may have multiple address
2-Customer may have multiple and unique contact numbers.
3-Customer may have multiple and unique email-id's.
while running the application, i am getting the MultipleBagFetchException becoz of multi collection or might be bcoz of wrong mapping., can any one help me...
thanks
first
public class Customer{
#Id
#GeneratedValue(generator = "uuid")
#Access(AccessType.PROPERTY)
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Type(type = "uuid-char")
#Column(columnDefinition = "VARCHAR(36)", name = DatabaseConstants.ID)
private UUID id;
private String firstName;
private String middleName;
private String lastName;
private Date dob;
#OneToOne(cascade = CascadeType.ALL)
private Gender gender;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "customer")
#JoinColumn(name="department_id")
#Embedded
private List<Address> address;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "customer")
#Embedded
private Set<Email> email;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "customer")
#Embedded
private Set<Mobile> mobile;
}
Second-
public class Address {
#Id
#GeneratedValue(generator = "uuid")
#Access(AccessType.PROPERTY)
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Type(type = "uuid-char")
#Column(columnDefinition = "VARCHAR(36)", name = DatabaseConstants.ID)
private UUID id;
private String country;
private String state;
private String city;
private String streetAddress;
private String zip;
private String addressType;
#ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
private Customer customer;
}
Third-
public class Email {
#Id
#GeneratedValue(generator = "uuid")
#Access(AccessType.PROPERTY)
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Type(type = "uuid-char")
#Column(columnDefinition = "VARCHAR(36)", name = DatabaseConstants.ID)
private UUID id;
#javax.validation.constraints.Email
private String emailId;
#ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
private Customer customer;
private boolean primary;
}
Fourth-
public class Mobile {
#Id
#GeneratedValue(generator = "uuid")
#Access(AccessType.PROPERTY)
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Type(type = "uuid-char")
#Column(columnDefinition = "VARCHAR(36)", name = DatabaseConstants.ID)
private UUID id;
private String mobileNumber;
private boolean primary;
#ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
private Customer customer;
}
You do not need #Embedded attribute on these
private List<Address> address;
private Set<Email> email;
private Set<Mobile> mobile;
#Embedded is required only when you want to embed a composite value. Here you have a simple one to many relationship between entities. Remove the #Embedded on the class members and #Embeddable on child classes if they are present and put #Entity if not already present.

Hibernate "ManyToOne ... references an unknown entity" exception

I just cannot get the relationship working between my two classes mapped to SQL tables with Hibernate.
The Role class:
#Entity
#Table(name = "role")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="name")
private String name;
#OneToMany(mappedBy="memberinfo")
private Set<Memberinfo> members;
...
}
And the Memberinfo class:
#Entity
#Table(name = "memberinfo")
public class Memberinfo {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id", nullable = false)
private int id;
#Column(name = "userid", nullable = false)
private String userid;
#Column(name = "email", nullable = false)
private String email;
#Column(name = "password", nullable = false)
private String password;
#Column(name = "salt", nullable = false)
private String salt;
#Column(name = "name", nullable = false)
private String name;
#Column(name = "address")
private String address;
#Column(name = "phonenum")
private String phonenum;
#ManyToOne(targetEntity=Role.class)
#JoinColumn(name="role_id")
private Role role;
...
}
When i try to fetch data from the DB, it connects, but throws an exception:
"HTTP Status 500 - #OneToOne or #ManyToOne on model.Memberinfo.role references an unknown entity: model.Role".
If i delete the variable "Role", then it works, and i can fetch the membership data, but i need the connection between the two tables, but in this case, the previously mentioned exception appears every time.
No other solutions on stackoverflow worked for me so far.
Any idea what am i doing wrong?
The "unknown entity error" can be thrown if the class is not actually an Entity (not annotated whith javax.persistence #Entity) or if the persitence provider doesn't "know" the class (package not scanned).
Is the Role class imported in Memberinfo the correct one ? Maybe you are importing another Role class from another library.

How to config Spring Security with JPA?

I need to add Spring Security into my project. What is the right way to do it? I have to entities User and UserRole and DAO and Services for them. I use EntityManager to access data. I read, that I just need to write implementation for UserDetails, but I don't know how to do it correctly. Here my code:
User.java
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty
private Integer id;
#Column(name = "username", length = 20, nullable = false)
#JsonProperty
private String username;
#Column(name = "password", nullable = false)
#JsonProperty
private String password;
#Column(name = "enabled", nullable = false)
#JsonProperty
private boolean enabled;
#Column(name = "email", nullable = false)
#JsonProperty
private String email;
#OneToMany(mappedBy = "user", cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
private Set<UserRole> userRoles;
//getters and setters
UserRole.java
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty
private Integer id;
#ManyToOne(optional = false)
#JoinColumn(name = "user_ID", referencedColumnName = "id", foreignKey = #ForeignKey(ConstraintMode.NO_CONSTRAINT))
private User user;
#Column(name="role")
#JsonProperty
private String role;
//getters and setters
What should I do?
I had wrote a blog post about exactly what you are looking for. see this post and I am pretty sure it will answer your question:
https://giannisapi.wordpress.com/2011/09/21/spring-3-spring-security-implementing-custom-userdetails-with-hibernate/
In the Service layer of UserDetails below, pay attention that it implements UserDetailsService from org.springframework.security.core.userdetails.UserDetailsService.
and also :
he loadUserByUsername methods return the result of the assembler.buildUserFromUserEntity . Simply put, what this method of the assembler does is to to construct a org.springframework.security.core.userdetails.User object from the given UserEntity DTO. The code of the Assembler class is given below:

Categories