I want to use Spring security to get the currently logged in user object but it returns a null value. I implemented the findByUsername method from the repository to test but it comes back with null/empty values and I've ensured data is in the database. What could I be doing wrong ?
Entity class
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String firstName ;
private String lastName;
#Column(name="user_name", unique=true)
private String userName;
private String password;
private String Gender;
Repository class
#Repository
public interface UserAccountRepository extends JpaRepository <User, Long> {
Optional<User> findById(Long id);
User findByUserName(String username);
Service class
#Transactional
#Service
public class UserAccountService implements UserDetailsService {
#Autowired
private UserAccountRepository userRepository;
private PasswordEncoder bCryptPasswordEncoder;
public User findByUserName(String username)
{
return userRepository.findByUserName(username);
}
Controller class
#GetMapping(value="/user/{username}")
public User findByUsername(String username) {
System.out.println("Username :" + username);
return userAccountService.findByUserName(username);
}
Application properties
spring.datasource.url=jdbc:mysql://localhost:3306/investmentpartners
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username= root
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.main.allow-bean-definition-overriding=true
spring.servlet.multipart.max-file-size=3000KB
spring.servlet.multipart.max-request-size=3000KB
spring.http.multipart.enabled=false
After adding spring.jpa.show-sql=true to application.properties file here is the query generated
Hibernate: select user0_.id as id1_4_, user0_.gender as gender2_4_, user0_.branch_id as branch_11_4_, user0_.created_date as created_3_4_, user0_.email as email4_4_, user0_.first_name as first_na5_4_, user0_.last_name as last_nam6_4_, user0_.password as password7_4_, user0_.phone_number as phone_nu8_4_, user0_.status as status9_4_, user0_.user_name as user_na10_4_ from user user0_ where user0_.user_name is null
null
You have forgotten to mark your path variable with annotation.
Solution:
#PathVariable String username
Controller class
#GetMapping(value="/user/{username}")
public User findByUsername(#PathVariable String username) {
System.out.println("Username :" + username);
return userAccountService.findByUserName(username);
}
Note:
Do not use System.out.println in your code to log out something, especially if you use Spring and your code runs in a server (Tomcat). Spring offers a perfect, easy to use way to write something to log:
public class YourController {
Logger logger = LoggerFactory.getLogger(YourController .class);
#GetMapping(...)
public String index(...) {
logger.debug("A DEBUG Message");
logger.info("An INFO Message");
// ...
}
}
Related
I work with small Spring boot app and I get the error org.hsqldb.HsqlException: user lacks privilege or object not found: USER0_.NAME during I compile. I have the same error before and now I reproduce it to the minimal amount of code. This is the project structure,
The error is triggered by the method findAll() from the controller,
#Controller
public class UserController {
#Autowired
private UserService userService;
#GetMapping(value = "/")
public String index() {
return "redirect:/users";
}
#GetMapping(value = "/users")
public String showAllUsers(Model model) {
// triggered by this line
model.addAttribute("users", userService.findAll());
return "list";
}
}
The important part of the error stack is,
org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [select user0_.id as id1_1_, user0_.name as name2_1_ from user user0_]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
......
Caused by: java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: USER0_.NAME in statement [select user0_.id as id1_1_, user0_.name as name2_1_ from user user0_]
.........
Caused by: org.hsqldb.HsqlException: user lacks privilege or object not found: USER0_.NAME
The entity class is provided,
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column
private String name;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
if (getId() != user.getId()) return false;
return getName().equals(user.getName());
}
#Override
public int hashCode() {
int result = (int) (getId() ^ (getId() >>> 32));
result = 31 * result + getName().hashCode();
return result;
}
}
The interfaces in the repository directory provided,
public interface UserRepository extends CrudRepository<User, Long> {
}
The user controller class is provided earlier. I can provide more info if required. My intention is will pass all the user values to the JSP page. I should mention, I don't have any user value now, the app will get the user info from a form and now it has nothing.
AS it asked from the comment, the services interface and classe are provided,
public interface UserService {
List<User> findAll();
User findById(Long idx);
void save(User user);
void delete(Long idx);
}
The service class implementation,
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
#Override
public List<User> findAll() {
return (List)userRepository.findAll();
}
#Override
public User findById(Long idx) {
return userRepository.findOne(idx);
}
#Override
public void save(User user) {
userRepository.save(user);
}
#Override
public void delete(Long idx) {
userRepository.delete(idx);
}
}
I use HSQL database and the application properties is provided,
server.port=8081
spring.mvc.view.prefix:/WEB-INF/jsp/
spring.mvc.view.suffix:.jsp
spring.thymeleaf.cache=false
spring.application.name=Bootstrap Spring Boot
spring.thymeleaf.enabled=true
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.devtools.restart.additional-paths=.
security.basic.enabled=true
security.user.name=john
security.user.password=123
spring.datasource.url=jdbc:hsqldb:file:db/registration;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.datasource.username=testuser
spring.datasource.password=testpassword
server.error.path=/error
server.error.whitelabel.enabled=false
# Keep the connection alive if idle for a long time (needed in production)
spring.datasource.testWhileIdle=true
spring.datasource.validationQuery=SELECT 1
# ===============================
# = JPA / HIBERNATE
# ===============================
# Use spring.jpa.properties.* for Hibernate native properties (the prefix is
# stripped before adding them to the com.boot.registration.entity manager).
# Show or not log for each sql query
spring.jpa.show-sql=true
# Hibernate ddl auto (create, create-drop, update): with "update" the database
# schema will be automatically updated accordingly to java entities found in
# the project
spring.jpa.hibernate.ddl-auto=create
# Allows Hibernate to generate SQL optimized for a particular DBMS
spring.messages.basename=validation
Update
Appearantly, none of the operations of the service interface works and provide the same set of errors. For example, if I put the code like,
#GetMapping(value = "/users")
public String showAllUsers(Model model) {
User user = new User();
user.setId(1L);
user.setName("Berlin");
userService.save(user);
// model.addAttribute("users", userService.findAll());
return "list";
}
I still have the same error Caused by: org.hsqldb.HsqlException: user lacks privilege or object not found: USER0_.NAME
What is the issue here?
I have excluded the JpaRepositoriesAutoConfiguration from the #SpringBootApplication and this apparently solved the issue here.
#EnableTransactionManagement
#SpringBootApplication(scanBasePackages = {"com.boot"} , exclude = JpaRepositoriesAutoConfiguration.class)
public class WebApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WebApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(WebApplication.class, args);
}
}
My springboot app tries to read data from two datasources(emwbis and backupemwbis). I've followed the below link in configuring my springboot app to read data from two different datasources.
http://www.baeldung.com/spring-data-jpa-multiple-databases
The current problem with my app is it is always reading data from the primary datasource(emwbis). I've written below code.
Model classes for primary and backup datasources:
package com.jl.models.primary;
#Entity
#Table(name = "crsbis",schema="emwbis")
#Data
public class CrsBIS {
#Id
private String id;
#NotNull
private String email;
package com.jl.models.backup;
import lombok.Data;
#Entity
#Table(name = "crsbis",schema="backupemwbis")
#Data
public class CrsBIS {
#Id
private String id;
#NotNull
private String email;
Datasource config classes for primary and backup datasources:
#Configuration
#PropertySource("classpath:persistence-multiple-db.properties")
#EnableJpaRepositories(basePackages = "com.jl.dao.backup", entityManagerFactoryRef = "crsBISBackUpEntityManager", transactionManagerRef = "crsBISBackupTransactionManager")
public class BackupCrsBISDatabaseConfig {
#Configuration
#PropertySource("classpath:persistence-multiple-db.properties")
#EnableJpaRepositories(basePackages = "com.jl.dao.primary", entityManagerFactoryRef = "crsBISEntityManager", transactionManagerRef = "crsBISTransactionManager")
public class CrsBISDatabaseConfig {
Repository interfaces for primary and backup datasources:
#Transactional
public interface CrsBISRepository extends JpaRepository<CrsBIS, String> {
public CrsBIS findById(String id);
}
#Transactional
public interface CrBisBackupRepository extends JpaRepository<CrsBIS, String>{
public CrsBIS findById(String id);
}
Persistent db proeprties file :
jdbc.driverClassName=com.mysql.jdbc.Driver
crsbis.jdbc.url=jdbc:mysql://localhost:3306/emwbis
backupcrsbis.jdbc.url=jdbc:mysql://localhost:3306/backupemwbis
jdbc.user=root
jdbc.pass=Password1
Controller class to test both the datasources :
#Controller
public class CrsBISController {
#Autowired
private CrsBISRepository crsBISRepository;
#Autowired
private CrBisBackupRepository crsBackupRepository;
#RequestMapping("/get-by-id")
#ResponseBody
public String getById(String id){
String email="";
try{
CrsBIS crsBIS = crsBISRepository.findById(id);
email = String.valueOf(crsBIS.getEmail());
}catch (Exception e) {
e.printStackTrace();
return "id not found!";
}
return "The email is : "+email;
}
#RequestMapping("/get-by-id-backup")
#ResponseBody
public String getByIdFromBackup(String id){
String email="";
try{
com.jl.models.backup.CrsBIS crsBIS = crsBackupRepository.findById(id);
email = String.valueOf(crsBIS.getEmail());
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
return "id not found!";
}
return "The email is : "+email;
}
Although, I've separated the database schemas in the model classes and in the database config file, both the methods in the controller class hit the same database (emwbis). I want getByIdFromBackup method in controller class to read the data from secondary database (backupemwbis).
Can someone please let me know the mistake in my code? Or you can suggest/guide me to achieve my goal?
From the first configuration file you're creating a primary datasource bean definition with the name myDatasource and in the second emf you're injecting the same datasource reference.
The Bean causing the problem is this
#Bean
#Primary
public DataSource myDataSource()
Just change the second Bean datasource name and use it in the second EMF.
public class BackupCrsBISDatabaseConfig {
...
#Bean
public DataSource backupDS() {
....
#Bean
public LocalContainerEntityManagerFactoryBean crsBISBackUpEntityManager() {
....
em.setDataSource(backupDS());
}
}
Hope this fixes it.
You have to explicitly request a TransactionManager implementation in your #Transactional usage:
#Transactional("crsBISTransactionManager")
//..
#Transactional("crsBISBackupTransactionManager")
//..
In my Spring project I want to update mysql table field according to the url :
I have url below:
localhost:9191/access/name/article?key=xyz
I want to fetch the article from url and then update the status and article field of the corrsponding mysql table
In my database I have the table name "user".
user(stu_id,name,email,article,status)
mysql query is:
UPDATE user
SET article='null', status=true
WHERE article='xyz'; here xyz=user.getArticle()
To achieve this I have done the below
User.java is:
public User(String article, String status) {
super();
this.article = article;
this.status = status;
}
UserDao.java
public interface UserDao {
public void updateUser(User user);
}
UserDaoImpl.java is:
#Transactional
#Repository("userDao")
public class UserDaoImpl implements UserDao {
#Autowired
private SessionFactory sessionFactory;
public void updateUser(User user) {
String hql = "update user set article = null,status=true"
+"where article=:key1";
sessionFactory.getCurrentSession().createQuery(hql)
.setParameter("key1", user.getArticle());
}
}
UserService.java is:
public interface UserService {
User updateUser(String article, String status);
}
UserServiceImpl.java is:
#Service("userService")
#Transactional(propagation = Propagation.SUPPORTS)
public class UserServiceImpl implements UserService {
public User updateUser(String article, String status) {
User user = new User(article,status);
userDao.updateUser(user);
return user;
return user;
}
UserController.java is:
//localhost:9191/access/name/article?key=xyz
#RequestMapping(value="/access/name/id", method=RequestMethod.GET)
public #ResponseBody String byParameter( User user, HttpServletRequest request) {
boolean ps=true;
String foo= request.getParameter("key");
userService.updateUserinfo(foo, ps);
return "signupLogin";
}
but it is showing error:
ERROR [] (ErrorCounter.java:56) - line 1:51: unexpected token: key
ERROR [] (ErrorCounter.java:56) - line 1:58: unexpected token: =
java.lang.IllegalArgumentException: node to traverse cannot be null!
at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1760)
at com.student.dao.UserDaoImpl.updateUser(UserDaoImpl.java:40)
at com.student.service.UserServiceImpl.updateUserinfo(UserServiceImpl.java:66)
where is the problem?What am I doing wrong??
Make following correction into sql query use User in place of user into query.
String hql = "update User set article = null, status = true where article = :key1";
if you don't want to change this method then you can use createSqlQuery method in place of createQuery method .
this solution may be help.
at com.student.dao.UserDaoImpl.updateUser(UserDaoImpl.java:40)
you were executing the wrong query.you should do like below code:
#Transactional
#Repository("userDao")
public class UserDaoImpl implements UserDao {
#Autowired
private SessionFactory sessionFactory;
public void updateUser(User user) {
String hql = "update user set article = null,status=true"
+"where article=:key1";
sessionFactory.getCurrentSession().createSQLQuery(hql)
.setParameter("key1", user.getArticle());
}
}
the syntax is like:
where user(this is the database table ) and article,status are the fields
I have a question as to how this service and its DAO object are performing persistence transactions.
The service is performing transactions on the database - but it is not using a DAOImpl object - it is instead using an object which is an instance of the interface - and naturally has no implementation of any method signatures. This, in my mind, should not be able to perform any meaningful actions. Am I overlooking something here?
Full link to code
http://www.byteslounge.com/tutorials/spring-with-hibernate-persistence-and-transactions-example
#Service
public class UserManagerImpl implements UserManager {
#Autowired
private UserDAO userDAO;
#Override
#Transactional
public void insertUser(User user) {
userDAO.insertUser(user);
}
#Override
#Transactional
public User getUserById(int userId) {
return userDAO.getUserById(userId);
}
#Override
#Transactional
public User getUser(String username) {
return userDAO.getUser(username);
}
#Override
#Transactional
public List<User> getUsers() {
return userDAO.getUsers();
}
}
public interface UserDAO {
void insertUser(User user);
User getUserById(int userId);
User getUser(String username);
List<User> getUsers();
}
#Service
public class UserDAOImpl implements UserDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public void insertUser(User user) {
sessionFactory.getCurrentSession().save(user);
}
#Override
public User getUserById(int userId) {
return (User) sessionFactory.
getCurrentSession().
get(User.class, userId);
}
#Override
public User getUser(String username) {
Query query = sessionFactory.
getCurrentSession().
createQuery("from User where username = :username");
query.setParameter("username", username);
return (User) query.list().get(0);
}
#Override
#SuppressWarnings("unchecked")
public List<User> getUsers() {
Criteria criteria = sessionFactory.
getCurrentSession().
createCriteria(User.class);
return criteria.list();
}
}
first of all , instance of an interface can not be created , reference variable can be created for interfaces. Nevertheless ,as i followed the link and found that you are learning Spring with Hibernate. Spring provide you a facility called Dependency Injection which is why there is #Autowire annotation in your UserManagerImpl class which means you have injected a dependency UserDAO in UserManagerImpl class , so on rum time ,spring will provide the instance of the class which implements UserDAO interface .What you are overlooking is thorough study of Spring concepts.by the way all the best .
I would like to know how to correctly store and retrieve my user in the session via Spring Security. I am using an AuthenticationManager. So far I am using the following approach which I know isn't the cleanest
public class UserController {
#Autowired
private UserService userService;
#RequestMapping(value="/myAccount", method=RequestMethod.GET)
public void myAccount(HttpServletRequest request){
//Verify Logged in user
User user = null;
UserProfile loggedinUser = (UserProfile) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if(loggedinUser != null){
user = userService.loadUserByUsername(loggedinUser.getUsername());
}
//Store User in session
Session session = request.getSession(true);
session.setAttribute("user", user);
}
}
I took a look at the answer here: Set User Object in session using Spring
But I don't fully understand how I should implement it. Could I possibly implement my User class like this
public class User implements UserDetails {
private String username;
private String password;
private String email;
......
}
And then modify my controller like this
public class UserController {
#Autowired
private UserDetailsService userDetailsService;
#RequestMapping(value="/myAccount", method=RequestMethod.GET)
public void myAccount(){
User user = (User)SecurityContextHolder.
getContext().getAuthentication().getPrincipal();
}
}
From my understanding, Spring will automatically load my custom User from the database and store it in the session?
Thanks