im new in hibernate.
I would like to build a simple autentication / login system in java with hibernate.
So let's say, i have a class User
public class User {
private int id;
private String username;
private String passwordHash;
...
}
Now i have a DAO to store a new User, and to get all users (as a list). Now im wondering, if its possible to get a list of users without the passwordHash field (for security reason)?
It would be nice if it was a question of configuration.
An other idea would be to split the User class into
public class User {
private int id;
private String username;
...
}
public class UserWithPassword extends User {
private String passwordHash;
...
}
So i could use UserWithPassword to store a new user into the database and use
the User class to query the list of all users (without password).
Any other suggestion?
Your split class won't work because you have to link a class to Hibernate.
Your DAO doesn't have to return the class itself. You can write an HQL query such:
select username
from User
See?
Then your DAO would have a method like public Collection getUserNames()
you can use
java.util.List temp = hibernateTemplate.find("select u from user u ");
you can take all user from temp;
but if you want authenticate,you can use spring security,i suggest
Related
I've recently tried to implement Spring Security into my web store project to distinguish between single users. Websites are working properly except there is one issue which I can't track to resolve. I have object called Customer within User class. Customer object has fields like id, balance, etc., and User has OneToOne relationship to Customer, so I can have single object for credentials and foreign key to specifics of user - his first name, last name, balance, owned products, etc.
I also have Product class which has ManyToOne relationship with Customer. It has its' own id, productCost, etc.
I'm using Spring MVC to take care of proper URL dispatching. When some action is taken, I'm using #AuthenticationPrincipal annotation to get currently logged Customer (through foreign key in User) and modify data regarding Customer linked with that foreign key.
When I modify Customer data through #AuthenticationPrincipal in controller, changes are immediate and they show up on website. But when I try to modify data through some DAO, for example by searching for Customer through id or try to get Customer that owns Product from Product getter (ManyToOne has reference to owning Customer), changes are not immediate. Database updates itself immediately and properly, like in first case, but collections in code and website state are not changed until I logout and login again - that's when data is updated. I suspect it may be due to fact that updating UserDetails updates data directly for currently logged user but then - how may I achieve same effect for Customer found by id?
Snippets of code:
Users.java:
#Entity
#Table(name="users")
public class Users {
#Id
#Column(name="username")
private String username;
#Column(name="password")
private String password;
#Column(name="enabled")
private boolean isActive;
#OneToMany(mappedBy="user")
private Set<Authorities> authorities;
#OneToOne
#JoinColumn(name="customer_id")
private Customer customer;
Product.java:
#Entity
#Table(name="product")
public class Product {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="name")
private String productName;
#Column(name="description")
private String productDescription;
#Column(name="category")
private String productCategory;
#Column(name="cost")
private int productCost;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="owner_id")
private Customer productOwner;
Customer.java:
#Entity
#Table(name="customer")
public class Customer {
//Class fields
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="balance")
private int balance;
#Column(name="first_name")
private String firstName;
#Column(name="last_name")
private String lastName;
#Column(name="email")
private String email;
#OneToMany(mappedBy="productOwner", fetch=FetchType.EAGER)
private List<Product> ownedProducts;
Piece of controller code:
#Autowired
CustomerService customerService;
#Autowired
ProductService productService;
/*(...)*/
#GetMapping("/showOffer/{offerId}")
public String getOffer(#PathVariable int offerId, Model theModel, #AuthenticationPrincipal MyUserDetails user) {
Product retrievedProduct = productService.findById(offerId);
if (user.getCustomer().getBalance() >= retrievedProduct.getProductCost())
{
Customer retrievedProductOwner = retrievedProduct.getProductOwner();
/* This is where changes aren't applied immediately and I need to logout and login to process them. */
retrievedProductOwner.setBalance(1000);
/* This is where changes are immediately shown and Java collections are updated: */
user.getCustomer().setBalance(user.getCustomer().getBalance()-retrievedProduct.getProductCost());
/* Code below is an attempt to force immediate changes by updating collections directly from database - but that approach doesn't work */
productService.delete(retrievedProduct.getId());
retrievedProduct.getProductOwner().getOwnedProducts().clear();
retrievedProduct.getProductOwner().setOwnedProducts(productService.listOwnerProducts(retrievedProduct.getProductOwner()));
}
else {
System.out.println("Insufficient funds!");
}
return "redirect:/home";
TL:DR
I use UserDetails object in controller and I am also using DAO for Customer used as foreign key in UserDetails. Using UserDetails directly updates data and everything works fine, using DAO doesn't make changes until I logout and login.
as far as i understand your changes are only commited when you log out .
just try to synchronize and commit any modification at the right time and it would be safer that you manage sessions and transactions at the same time so you don't get any sort of incoherence when you do that. then tell me about the results .
Check whether CTRL+F5 in your browser (force cache clearance) updates your data similarly to logging out and back in. If so, it's a question of cached information. (this and (3) may occur at the same time)
Alternatively ... or perhaps complementarly ... your data fetch reqeust may be called before the database update/commit operation is completed. If so, it should become evident if you run distinct update and show routines. i.e. turn A into B, then into C, and you'd get something like B when you're expecting C... A instead of B... etc.
Lastly, depending on how you set up your back end, it is possible that you only populate whatever form you use for the front end exactly once, instead of dynamically querying the database whenever you access that form.
I'm afraid I have a small problem with my project with Spring and MongoDB.
I have saved a user, which is shown under Email,Name and another object(workplace).
private String email;
private String name;
private WorkPlace workPlace;
I need the possibility to change the Workplace. I have not found anything reasonable in the Internet for an update. Only a "save" method to update the object.
The problem is, if I want to update the object, he takes the user, changes the Workplace and creates a new object. But I don't need a new object. The object is unique by its email address, because it only exists once.
I need only to change the Workplace
#PostMapping("/update")
public User update(#RequestParam String email, #RequestBody Workplace workplace ) {
User u = repository.findByEmail(email);
u.setWorkplace(workplace);
return repository.save(u);
}
I have set the repository as follows:
import org.springframework.data.mongodb.repository.MongoRepository;
#Repository
public interface ModelRepository extends MongoRepository<User, String> {
public User findByEmail(String email);
}
You need to have an #Id annotated property at your User class. Otherwise Spring Data MongoDB does not find an existing identifier and will do an insert of the object.
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document
#Document(collection="users")
class User {
#Id
private String email;
private String name;
private Workplace workplace;
}
If an entity is set, then a save instead of an insert is done.
I am creating a web application only using Java and not any framework.
I am at this point where I have to get data from the Database. I am doing this using DAO pattern but I have a problem to understand some logic about relationships (one-to-one, one-to-many, and many-to-many).
To understand my problem better I will explain by taking an exact example.
I have two entities (tables) in the database User and Role. The entity User has attributes id, name, lastname, username, and password, and the table Role has attributes id, role, description.
From this I have the relation that one User can have more than one Role (so a user can be both a simple user and an admin of the web app), and one Role can be in many User. From this point I creat another table tha represents many-to-many relationship named UserRoles that has attributes user_id, role_id.
Now in Java I have a class named `User:
public class User
{
private int id; (with getters and setters)
private String name; (with getters and setters)
private String lastname; (with getters and setters)
private String username; (with getters and setters)
private String password; (with getters and setters)
// and two constructors with and without parameters together with toString method
}
and the interface named UserDAO:
public interface UserDAO
{
public User find(intid);
public User find(String email, String password);
public List<User> users();
public void create(User user);
public void update(User user);
public void delete(User user);
public boolean existEmail(String email);
public void changePassword(User user);
}
I have the class for manipulation with MySQL queries named UserDAOJDBC:
public class UserDAOJDBC implements UserDAO
{
private static final String FIND_BY_ID = "SELECT * FROM user WHERE id=?";
#Override
public User find(int id) {
return find(FIND_BY_ID, id);
}
private User find(String sql, Object... values){
User user = null;
try {
ResultSet resultSet = DBConnectionPool.executeQuery(sql, values);
if(resultSet.next()){
user = new User();
user.setId(Integer.parseInt(resultSet.getString("id")));
user.setName(resultSet.getString("name"));
user.setLastname(resultSet.getString("lastname"));
user.setUsername(resultSet.getString("username"));
user.setPassword(resultSet.getString("password"));
}
DBConnectionPool.getConnection().close();
} catch (Exception e) {
System.out.println(e);
}
return user;
}
}
Now when I want to get Role for one User what is a better practice?
So far I have this solution:
1) I have to include Role in the User class:
public class User
{
private int id; (with getters and setters)
private String name; (with getters and setters)
private String lastname; (with getters and setters)
private String username; (with getters and setters)
private String password; (with getters and setters)
private List<Role> roles; (with getters and setters)
// and two constructors with and without parameters together with toString method
}
and create in class UserDAOJDBC a method named findWithRoles that makes the join with the tables as:
SELECT * FROM user AS u INNER JOIN userroles as ur ON u.id = ur.user_id
and then the second query that goes through results of the previous one:
SELECT * FROM role AS r INNER JOIN userroles as ur ON r.id = ur.role_id
and from the ResultsSet of this query to populate the array List<Role> roles.
You don't need to include Role into the User class (even though you can). It is enough to create the UserRoles table and read the data from it. You should probably create UserRolesDAO class that will implement all the methods for you to find all the roles of a specific user, and all the users to specific role, as well as save new user, role combination and read it back.
I have an example on github where I combined Students and Courses in exactly same way using JDBC and DAO pattern so feel free to take a look.
Blog post about dao
I had a method in a ProjectRepository that looked something like this:
findByUserID(int userID);
This would list all projects that reference a certain user. Because of other requirements, I now need to reference the User from the Project, instead of just the userID, like so:
#ManyToOne
#JoinColumn(name = "userID", referencedColumnName = "userID")
private User user;
Which used to just be:
int userID;
So I replaced the method with:
findByUser(User user);
But this requires an extra call to the database to get the User object for a given userID. Is there a way to use the first method with my new class? If I just keep the first method, I get a
org.springframework.data.mapping.PropertyReferenceException: No property ID found for type User! Traversed path: Project.user.
Is this possible without writing a custom query?
Assuming the User class contains is defined as:
public class User {
private int userId;
public User(int userId) {
this.userId = userId;
}
//getters setters ommitted
}
and the Project class has a User object in it like so:
public class Project {
private User user;
public Project() {
}
//rest ommitted
}
It should according to the documentation be able to write a custom query in the repository that access the nested properties like project.user.userId by writing
findByUserUserId(int userId);
Or at least that's what I understood from reading the docs here
Try using the #PrimaryKeyJoinColumn annotation.
I'm creating a directory with spring boot, and I add the library Spring Ldap.
I created my odm of User and it works, but I don't know how to map attribute from another entry.
My users are in ou=people,dc=mycompany,dc=com
The user belongs to an unit in ou=units,dc=mycompany,dc=com
The user have 0 or 1 manager in `ou=people,dc=mycompany.' same as users
The user have 0 or more subsidiaries no attribute for that, I have to find it with the help of manager attribute.
Here my code:
#Entry( objectClasses = { "person", "top" }, base = "ou=People" )
public final class User{
#Id private Name dn;
private String fullname;
private String mail;
etc...
}
I would like to add private User manager and private String unit and private List<User> subsidiaries but I dont know how to map/link to another Entry.
There is currently no support for relations in Spring LDAP ODM. I'm not sure it would be quite worth the effort (since LDAP is not really a relational database anyway), but it could possibly be something we could take a shot at if the demand for it is high.
Facing the same issue, I've used a transient attribute in my User class :
#Attribute(name = "manager", syntax = "1.3.6.1.4.1.1466.115.121.1.12")
private Name managerName;
#Transient
private User manager;
Of course, you have to deal with the manager attribute yourself. Add the following code in your UserService class :
public User findUser(String uid) {
User user = getRepo().findByUid(uid);
if(null != user.getManagerName()) {
User manager = getRepo().findOne(user.getManagerName());
user.setManager(manager);
}
return user;
}
You have to write something similar when saving your user object, in order to fill the managerName attribute with its new value if required.