This question already has answers here:
Springboot Security hasRole not working
(3 answers)
Closed 4 years ago.
I am using spring security in my spring boot app.
My app works well with in-memory authentication.
But when users are loaded from the database it does not authenticate. It returns 403 access denied error code. UserDetailsService is able to fetch the user information from the database but I dont know where it is going wrong. I am new to spring.
here is my complete code related to security
User.java
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import lombok.Data;
#Entity
#Table(name = "user")
#Data
public class User {
#Id
#NotNull
#GeneratedValue(strategy = GenerationType.AUTO)
private Long userId;
#Column(name = "USERNAME", unique = true)
#NotNull
private String username;
#Column(name = "PASSWORD")
#NotNull
private String password;
#Column(name = "DISPLAY_NAME")
private String displayName;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "id")
private Set<Role> userRoles;
private String profilePicturePath;
}
Role.java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
#Entity
#Table(name = "roles")
#Data
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String role;
}
UserRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.cloudsofts.cloudschool.people.users.pojos.User;
#Repository("userRepository")
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
RoleRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.cloudsofts.cloudschool.people.users.pojos.Role;
#Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
}
UserService.java
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import com.cloudsofts.cloudschool.people.users.pojos.User;
import com.cloudsofts.cloudschool.people.users.repositories.UserRepository;
#Service
public class UserService {
#Autowired
UserRepository userRep;
#Autowired
private PasswordEncoder passwordEncoder;
public List<User> getAllUsers() {
List<User> users = userRep.findAll();
return users;
}
public void addUser(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
userRep.save(user);
}
public void updateUser(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
userRep.save(user);
}
public void deleteUser(Long id) {
userRep.delete(id);
}
public User getUser(Long id) {
return userRep.findOne(id);
}
}
RoleService.java
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.cloudsofts.cloudschool.people.users.pojos.Role;
import com.cloudsofts.cloudschool.people.users.repositories.RoleRepository;
#Service
public class RoleService {
#Autowired
RoleRepository userRoleRep;
public void addUserRole(Role role) {
userRoleRep.save(role);
}
public void updateUserRole(Role role) {
userRoleRep.save(role);
}
public void deleteUserRole(Long id) {
userRoleRep.delete(id);
}
public Role getUserRole(Long id) {
return userRoleRep.findOne(id);
}
public List<Role> getAllUserRoles() {
return userRoleRep.findAll();
}
}
CustomUserDetails.java
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import lombok.Data;
#Data
public class CustomUserDetails implements UserDetails {
private static final long serialVersionUID = 1L;
private User user;
public CustomUserDetails(final User user) {
this.user = user;
}
public CustomUserDetails() {
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
final Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
Set<Role> roles = null;
if (user != null) {
roles = user.getUserRoles();
}
if (roles != null) {
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority(role.getRole()));
}
}
return authorities;
}
#Override
public String getPassword() {
return user.getPassword();
}
#Override
public String getUsername() {
return user.getUsername();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
CustomUserDetailsService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.cloudsofts.cloudschool.people.users.pojos.CustomUserDetails;
import com.cloudsofts.cloudschool.people.users.pojos.Role;
import com.cloudsofts.cloudschool.people.users.pojos.User;
import com.cloudsofts.cloudschool.people.users.repositories.UserRepository;
#Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException(username);
} else {
System.out.println("______________________________________________________________");
System.out.println("username: " + user.getUsername());
System.out.println("password: " + user.getPassword());
System.out.println("Roles: ");
for (Role role : user.getUserRoles()) {
System.out.println(role.getRole());
}
System.out.println("______________________________________________________________");
return new CustomUserDetails(user);
}
}
}
SecurityConfig.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.cloudsofts.cloudschool.security.CustomUserDetailsService;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Qualifier("userDetailsService")
#Autowired
CustomUserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
try {
auth.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder());
System.out.println("_________________________________________________");
String username = SecurityContextHolder.getContext().getAuthentication().getName();
System.out.println("_________________________________________________");
System.out.println("You have logged in as " + username);
System.out.println("_________________________________________________");
} catch (Exception e) {
System.out.println("_________________________________________________");
System.out.println(e.getMessage());
System.out.println("_________________________________________________");
}
}
#Bean(name = "passwordEncoder")
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/*
* #Autowired public void configureGlobal(AuthenticationManagerBuilder auth)
* throws Exception {
* auth.inMemoryAuthentication().withUser("student").password("student").roles(
* "student").and().withUser("admin") .password("admin").roles("admin"); }
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// http.authorizeRequests().anyRequest().permitAll();
// http.authorizeRequests().antMatchers("/api/**").permitAll();
http.authorizeRequests().antMatchers("/student/**").hasAnyRole("student", "admin");
http.authorizeRequests().antMatchers("/api/admin/**").hasRole("admin");
http.authorizeRequests().antMatchers("/library/**").hasAnyRole("librarian", "admin");
http.httpBasic();
// http.formLogin().and().logout().logoutSuccessUrl("/login?logout").permitAll();
}
}
Screenshots
Postman Screenshot
Browser Screenshot
Users in the db
Roles in the db
User-Role mapping
Console output after giving the credentials
You seems to using the BCryptPasswordEncoder to encrypt and decrypt password. But 'Users' table screenshot shows the password in plain text. Can you validate the place where you are saving or updating the user, it is actually encoding the password and also the password encoder bean is of type 'BCryptPasswordEncoder'
I got the problem solved.
I had to add ROLE_ as a prefix to the roles.
Now everything works fine
Related
I try to realise an authorization, but cannot get the cause of this problem: Encoded password does not look like BCrypt
My actions sequence: open localhost:8080/login, write "user" in login input and "password" in password (user with such login and password is guaranteed to exist), submit, here the problem appears (Encoded password does not look like BCrypt is written in console), login is failed.
I am new at Spring, so I need your experienced advice. I guess, the reason is in the auth.userDetailsService(userService).passwordEncoder(passwordEncoder()); in protected void configure(AuthenticationManagerBuilder auth) method in WebSecurityConfig.java, but I cannot apply any solution I've found.
WebSecurityConfig.java
package com.todo.todo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import com.todo.todo.services.UserService;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig{
#Autowired
private UserService userService;
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.antMatchers("/",
"/index",
"/users",
"/registrate",
"/deleteuser/**",
"/webjars/**").permitAll()
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginPage("/login")
.permitAll()
)
.logout((logout) -> logout.permitAll());
return http.build();
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
UserService.java
package com.todo.todo.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.todo.todo.repositories.UserRepository;
#Service
public class UserService implements UserDetailsService{
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetails userDetails = userRepository.findByUsername(username);
if(userDetails == null) throw new UsernameNotFoundException("No such username");
return userDetails;
}
}
UserRepository.java
package com.todo.todo.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import com.todo.todo.models.User;
public interface UserRepository extends JpaRepository<User, Long>{
User findByUsername(String username);
}
UserController.java
package com.todo.todo.controllers;
import java.time.Instant;
import java.util.Collections;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;
import com.todo.todo.models.Role;
import com.todo.todo.models.User;
import com.todo.todo.repositories.UserRepository;
#Controller
public class UserController {
private final String registratePage = "registrate";
// private final String loginPage = "login";
private final String redirectLoginPage = "redirect:/login";
private final String redirectUsersPage = "redirect:/users";
#Autowired
private UserRepository userRepository;
#GetMapping("/users")
public ModelAndView getHomePage(#AuthenticationPrincipal User user){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("users");
modelAndView.addObject("users", userRepository.findAll());
return modelAndView;
}
#GetMapping("/deleteuser/{id}")
public String deleteTask(#PathVariable("id") Long id, Model model){
User user = userRepository.findById(id).orElseThrow(() -> new NoSuchElementException("User not found by id = " + id));
userRepository.delete(user);
return redirectUsersPage;
}
#GetMapping("/registrate")
public String getRegistratePage(){
return registratePage;
}
#PostMapping("/registrate")
public String registrateUser(#Valid User user, Map<String, Object> map){
User userFromDatabase = userRepository.findByUsername(user.getUsername());
if(userFromDatabase != null){
map.put("message", "User has been already registrated!");
return registratePage;
}
user.setCreatedDate(Instant.now());
user.setRoles(Collections.singleton(Role.USER));
userRepository.save(user);
map.put("message", "User has been successfully registrated!");
return redirectLoginPage;
}
}
User.java
package com.todo.todo.models;
import java.time.Instant;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import lombok.Getter;
import lombok.Setter;
#Getter
#Setter
#Entity
#Table(name = "usr")
public class User implements UserDetails{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotBlank(message = "Fill username")
private String username;
#NotBlank(message = "Fill password")
private String password;
private Instant createdDate;
#ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
#CollectionTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"))
#Enumerated(EnumType.STRING)
private Set<Role> roles;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
this.createdDate = Instant.now();
this.roles = new HashSet<>();
}
#Override
public String toString() {
return String.format("User{id=%d, username='%s', password='%s', createdDate='%s'}",
id, username, password, createdDate);
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return getRoles();
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>LOGIN</title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<span th:text="${message}"></span>
<form th:action="#{/login}" method="POST">
<div><label> Username : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
Create new user
To users
</body>
</html>
I solved this
WebSecurityConfig.java
package com.todo.todo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.todo.todo.services.UserService;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.antMatchers("/",
"/index",
"/tasks",
"/users",
"/registrate",
"/logout",
"/deleteuser/**",
"/create",
"/delete/**",
"/update/**",
"/create_task",
"/update_task",
"/h2-console/**",
"/webjars/**").permitAll()
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginPage("/login")
.permitAll()
)
.logout((logout) -> logout.permitAll());
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userService)
.passwordEncoder(new BCryptPasswordEncoder());
}
}
UserController.java
Added encoding password in #PostMapping("/registrate")
// some imports here
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
// some methods here
#PostMapping("/registrate")
public String registrateUser(#Valid User user, Map<String, Object> map){
User userFromDatabase = userRepository.findByUsername(user.getUsername());
if(userFromDatabase != null){
map.put("message", "User has been already registrated!");
return registratePage;
}
String encodedPassword = new BCryptPasswordEncoder().encode(user.getPassword());
user.setPassword(encodedPassword);
user.setCreatedDate(Instant.now());
user.setRoles(Collections.singleton(Role.USER));
userRepository.save(user);
map.put("message", "User has been successfully registrated!");
return redirectLoginPage;
}
I have a CustomerUserDetailsService class, which is part of an implementation of Spring Boot authentication. I have tested my code manually, and it works correctly, allowing me to successfully log in to my app. However, I am unable to work out how to test the CustomerUserDetailsService.
As a unit test, I believe I would need to mock the userRepository member variable, but whatever I try in my test fails, the reason being userRepository is set to null. I've tried adding the #Repository annotation to userRepository but am told that is not allowed because it is an interface. There's also the fact that loadUserByUsername returns an instance of CustomUserDetails, which is just an implementation of an interface, so I have no idea how I'd mock that dependency?
I've also tried doing some kind of integration test but had similar issues, probably due to incorrect annotations on the test itself. In an ideal world, I'd prefer a unit test and would be extremely grateful for any guidance as to how to set it up.
These are the relevant classes...
CustomerUserDetailsService:
package com.phil.urlshortener.security;
import com.phil.urlshortener.model.User;
import com.phil.urlshortener.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
public class CustomUserDetailsService implements UserDetailsService {
#Autowired private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
return new CustomUserDetails(user);
}
}
User:
package com.phil.urlshortener.model;
import lombok.Data;
import javax.persistence.*;
#Data
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false, unique = true, length = 50)
private String username;
#Column(nullable = false, length = 64)
private String password;
}
UserRepository:
package com.phil.urlshortener.repositories;
import com.phil.urlshortener.model.User;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Long> {
#Query("SELECT u FROM User u WHERE u.username = ?1")
User findByUsername(String username);
}
CustomUserDetails:
package com.phil.urlshortener.security;
import com.phil.urlshortener.model.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
public class CustomUserDetails implements UserDetails {
private final User user;
public CustomUserDetails(User user) {
this.user = user;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
#Override
public String getPassword() {
return user.getPassword();
}
#Override
public String getUsername() {
return user.getUsername();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
Maybe you forgot to use mockito annotation #RunWith(MockitoJUnitRunner.class).
Here it's the unit test for CustomUserDetailsService :
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
public class CustomUserDetailsService {
#Mock
private UserRepository userRepository;
private CustomUserDetailsService customUserDetailsService;
#Before
public void setUp() throws Exception {
customUserDetailsService = new CustomUserDetailsService(userRepository);
}
#Test
public void GIVEN_username_THEN_return_user_details() {
//Arrange
final String username = "existingUserName";
final User user = mock(User.class);
when(userRepository.findByUsername(username)).thenReturn(user);
//Act
final UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
//Assert
assertNotNull(userDetails);
assertEquals(user, ReflectionTestUtils.getField(userDetails, "user"));
}
}
I finished creating a simple Spring-boot project in which I can enter users and through the Get command it returns me the name (from a list of identical names) with the oldest entry date. Unfortunately, every time I ask for Get it returns this ERROR:
D:\>curl -G localhost:8080/demo/first?=Biagio
{"timestamp":"2020-10-04T22:46:35.996+00:00","status":404,"error":"Not Found","message":"","path":"/demo/first"}
And to each of my POST / Add requests like this ERROR:
D:\>curl localhost:8080/demo/add -d name=Giovanni -d email=giovanni#gmail.com -d surname=Jackie
{"timestamp":"2020-10-04T22:40:51.928+00:00","status":404,"error":"Not Found","message":"","path":"/demo/add"}
Below I enter the interested parties of my project to try to get something out of it, because I have been stuck for days now
AccessingDataMysqlApplication.java
package com.example.accessingdatamysql;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
public class AccessingDataMysqlApplication {
public static void main(String[] args) {
SpringApplication.run(AccessingDataMysqlApplication.class, args);
}
}
MainController.java
package com.example.accessingdatamysql.rest;
import javax.persistence.NoResultException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.example.accessingdatamysql.model.UserDto;
import com.example.accessingdatamysql.service.UserService;
#RestController
#RequestMapping("/demo")
public class MainController {
#Autowired
private UserService userService;
#Transactional
//#RequestMapping(value = "/add/", method = RequestMethod.POST)
#PostMapping(path="/demo/add")
public String addNewUser(#PathVariable("name") String name, #PathVariable("email") String email,
#PathVariable("surname") String surname) {
UserDto n = new UserDto();
n.setName(name);
n.setSurname(surname);
n.setEmail(email);
userService.create(n);
return "User Saved in DB";
}
#SuppressWarnings({ "rawtypes", "unchecked" })
//#RequestMapping(value = "/fetchUser/{name}", method = RequestMethod.GET)
#GetMapping("/demo/first")
public ResponseEntity<UserDto> fetchUser(#PathVariable("name") String name) {
System.out.println(name);
try {
UserDto namefound = userService.findFirstByName(name);
System.out.println("Name found");
ResponseEntity<UserDto> user = new ResponseEntity<UserDto>(namefound, HttpStatus.OK);
return user;
} catch(NoResultException ne) {
System.out.println("User not found");
return new ResponseEntity("User not found with name : " + name, HttpStatus.NOT_FOUND);
}
}
}
UserService.java
package com.example.accessingdatamysql.service;
import org.springframework.stereotype.Service;
import com.example.accessingdatamysql.model.UserDto;
#Service
public interface UserService {
UserDto findFirstByName(String name);
void create(UserDto user);
}
UserServiceImpl.java
package com.example.accessingdatamysql.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.example.accessingdatamysql.model.UserDto;
import com.example.accessingdatamysql.model.UserEntity;
import com.example.accessingdatamysql.repo.UserRepository;
import com.example.accessingdatamysql.util.UserMapper;
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
#Autowired
UserMapper mapper;
#Override
public UserDto findFirstByName(String name) {
UserEntity entity = userRepository.findFirstByName(name);
return mapper.toDtoMapper(entity);
}
#Override
public void create(UserDto user) {
UserEntity entity = mapper.toEntityMapper(user);
userRepository.create(entity);
}
}
UserMapper.java
package com.example.accessingdatamysql.util;
import org.mapstruct.Mapper;
import com.example.accessingdatamysql.model.UserDto;
import com.example.accessingdatamysql.model.UserEntity;
#Mapper(componentModel = "spring")
public interface UserMapper {
public UserEntity toEntityMapper (UserDto user);
public UserDto toDtoMapper (UserEntity userEntity);
}
UserRepository.java
package com.example.accessingdatamysql.repo;
import org.springframework.stereotype.Repository;
import com.example.accessingdatamysql.model.UserEntity;
#Repository
public interface UserRepository {
UserEntity findFirstByName(String name);
void create(UserEntity entity);
}
UserRepositoryImpl.java
package com.example.accessingdatamysql.service;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.springframework.stereotype.Component;
import com.example.accessingdatamysql.model.UserEntity;
import com.example.accessingdatamysql.repo.UserRepository;
#Component
public class UserRepositoryImpl implements UserRepository {
private final EntityManager em;
public UserRepositoryImpl(EntityManager entityManager) {
this.em = entityManager;
}
#Override
public UserEntity findFirstByName(String name) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<UserEntity> criteria = builder.createQuery(UserEntity.class);
Root<UserEntity> root = criteria.from(UserEntity.class);
criteria.select(root).where(builder.equal(root.get("name"), name));
criteria.orderBy(builder.asc(root.get("timestamp")));
TypedQuery<UserEntity> query = em.createQuery(criteria).setMaxResults(1);
return query.getSingleResult();
}
#Override
// per la creazione//
public void create(UserEntity entity) {
em.persist(entity);
}
}
UserDto.java
package com.example.accessingdatamysql.model;
import java.io.Serializable;
import java.sql.Timestamp;
public class UserDto implements Serializable {
/**
*
*/
private static final long serialVersionUID = -7621330660870602403L;
/**
*
*/
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Timestamp getTimestamp() {
return timestamp;
}
public void setTimestamp(Timestamp timestamp) {
this.timestamp = timestamp;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
private Timestamp timestamp;
private String email;
private String surname;
}
If you need I can also insert User.java and the pom, but the pom has no problems as the dependencies are all correct.
You have an additional demo in your path descriptions for GET and POST methods, you should remove it:
#GetMapping("/demo/first")
#PostMapping(path = "/demo/first")
It should be :
#GetMapping("/first")
#PostMapping(path = "/first")
This because you have already defined demo in the RequestMapping annotation in the class level.
i'm building a Java SpringBoot(Back-End),Vuejs(front)aplication , and im on this part of seting the web security application.
On my User Class the constructor might be like this :
package com.miniAmazon;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.security.core.GrantedAuthority;
import javax.persistence.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO,generator = "native")
#GenericGenerator(name="native",strategy="native")
private Long id;
#OneToMany(mappedBy = "users",fetch= FetchType.EAGER)
Set<Product> productsSet= new HashSet<>();
#OneToMany(mappedBy="users", fetch=FetchType.EAGER)
Set<Purchase> purchaseSet=new HashSet<>();
private String userRole;
private String userName;
private String userEmail;
private String userPassword;
public User(){}
public User( String userEmail,String userName,String userPassword,String userRole){
this.userName=userName;
this.userEmail=userEmail;
this.userPassword=userPassword;
this.userRole=userRole;
}
public void addPurchase(Purchase purchase){ purchaseSet.add(purchase);}
public Set<Purchase>getUserPurchaseSet(){
return purchaseSet;
}
////////////////////////////////////////////setter/////////////////////////////////////////////
///////////////////////////////////////////getters////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
#Override
xxxxx
}
}
user repository like this:
package com.miniAmazon;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
#RepositoryRestResource
public interface UserRepository extends JpaRepository<User,String> {
User findByuserName (String usertName);
}
and the web security application code was settled in this way:
package com.miniAmazon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.Date;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
public PasswordEncoder passwordEncoder(){
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Bean
public CommandLineRunner initData(ProductRepository productRepository, UserRepository userRepository, PurchaseRepository purchaseRepository){
return(args)->{
User user1=new User("lolo#gmail.com","lolo gomex",passwordEncoder().encode("24"),"buyer");
User user2=new User("jhony#gmail.com","Jack Ripper",passwordEncoder().encode("mole"),"buyer");
User user3=new User("gothic#gmail.com","demo gago",passwordEncoder().encode("adu"),"seller");
User user4=new User("grau#gmail.com","grau gomex",passwordEncoder().encode("24"),"seller");
User user5=new User("goiy#gmail.com","divan Ripper",passwordEncoder().encode("mole"),"buyer");
User user6=new User("gatti#gmail.com","guti gago",passwordEncoder().encode("adu"),"admin");
userRepository.save(user1);
userRepository.save(user2);
userRepository.save(user3);
userRepository.save(user4);
userRepository.save(user5);
userRepository.save(user6);
};
}
}
#Configuration
#EnableWebSecurity
class WebSecurityConfiguration extends GlobalAuthenticationConfigurerAdapter {
#Autowired
UserRepository userRepository;
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(inputName-> {
User user =userRepository.findByuserName(inputName);
if (user != null) {
return new User(user.getUserName(), user.getUserPassword(),
AuthorityUtils.createAuthorityList("USER"));--------------------ERROR
} else {
throw new UsernameNotFoundException("Unknown user: " + inputName);
}
});
}
}
#Configuration
#EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// http.cors();///de heroku tambien
http.authorizeRequests()
.antMatchers("/mini/all_products").permitAll()
.antMatchers("mini/all_products/user_dashboard/purchase/{id}").permitAll()
.antMatchers("/mini/all_product/registering").permitAll()
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/rest/**").hasAuthority("ADMIN")
.antMatchers("/**").hasAuthority("USER")
.anyRequest().fullyAuthenticated();
/////Autorizaciones y permisos para los distintos niveles de seguridad que tendria el usuario segun su casificacion
http.formLogin()
.usernameParameter("name")
.passwordParameter("password")
.loginPage("/api/login");
//
http.logout().logoutUrl("/api/logout");
http.csrf().disable();
http.exceptionHandling().authenticationEntryPoint((req, res, exc) -> res.sendError(HttpServletResponse.SC_UNAUTHORIZED));
http.formLogin().successHandler((req, res, auth) -> clearAuthenticationAttributes(req));
http.formLogin().failureHandler((req, res, exc) -> res.sendError(HttpServletResponse.SC_UNAUTHORIZED));
http.logout().logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler());
// http.headers().frameOptions().disable();
http.headers().frameOptions().sameOrigin();
}
private void clearAuthenticationAttributes(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
}
}
}
but keeps throwing me an error in the first WebSecurityConfiguration in the cosntructor of the new User, saying once i hover it
Cannot resolve constructor 'User(java.lang.String, java.lang.String, java.util.List<org.springframework.security.core.GrantedAuthority>)'
Any idea about why this is happening .Really sorry for having exposed all this code!!.
And thanks in advance!!!
I have checked your code. In your WebSecurityConfig class
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(inputName-> {
User user =userRepository.findByuserName(inputName);
if (user != null) {
return new User(user.getUserName(), user.getUserPassword(),
AuthorityUtils.createAuthorityList("USER"));--------------------ERROR
}
});
}
You are returning user object like this :
return new User(user.getUserName(),
user.getUserPassword(),
AuthorityUtils.createAuthorityList("USER"));
which is wrong.
Because you have created constructor with different argument:
public User(String userEmail,
String userName,
String userPassword,
String userRole);
So pass arguments correctly. It will work.
You can also return like this:
return new User(null, user.getUserName(), user.getUserPassword(),
AuthorityUtils.createAuthorityList("USER"));
You should return org.springframework.security.core.userdetails.User instead of your com.miniAmazon.User:
if (user != null) {
return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getUserPassword(),
AuthorityUtils.createAuthorityList("USER"));
} else {
throw new UsernameNotFoundException("Unknown user: " + inputName);
}
since the loadUserByUsername method from UserDetailsService return a org.springframework.security.core.userdetails.UserDetails instance and org.springframework.security.core.userdetails.User implements org.springframework.security.core.userdetails.UserDetails.
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
This test project becouse of I don't know how I inject #AuthenticationPrincipal annotation in method ,I have some problem,#AuthenticationPrincipal UserDetails throws exception
UserDetails userDetails = SecurityContextHolder.getContext().getAuthentication().getPrincipal()
is working not problem but I want to inject this annotation in method how can I do ?
When I added annotation in method this exception is thrown
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.security.core.userdetails.UserDetails
How can I inject #AuthenticationPrincipal to index method in MainControll class ?
How can I solve this situation ?
MainControll.class
package com.sencerseven.springsecurityauth.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class MainController {
#RequestMapping(value = {"/"})
public ModelAndView index(#AuthenticationPrincipal UserDetails userDetails) {
ModelAndView mv = new ModelAndView("index");
mv.addObject("user", userDetails);
return mv;
}
#RequestMapping(value = {"/login"})
public ModelAndView loginPage(#RequestParam(name="error",required = false)String error,
#RequestParam(name="logout",required = false)String logout) {
ModelAndView mv = new ModelAndView("login");
mv.addObject("userClickLoginPage",true);
return mv;
}
#RequestMapping("/perform-logout")
public String logout(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication != null) {
new SecurityContextLogoutHandler().logout(httpServletRequest, httpServletResponse, authentication);
}
return "redirect:/";
}
}
This class is my main controller
WebSecurityConfig.class
package com.sencerseven.springsecurityauth.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
#Bean
public static BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Configuration
public static class HomeConfigLogin extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").permitAll().and()
.formLogin().loginPage("/login").usernameParameter("username").passwordParameter("password")
.defaultSuccessUrl("/", true).loginProcessingUrl("/login").and().logout().and().exceptionHandling()
.accessDeniedPage("/").and().csrf();
}
}
}
MyUserDetailService
package com.sencerseven.springsecurityauth.security;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.sencerseven.springsecurityauth.dao.UserDAO;
import com.sencerseven.springsecurityauth.dto.Role;
#Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
#Autowired
private UserDAO userDAO;
#Transactional
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
com.sencerseven.springsecurityauth.dto.User user = userDAO.findByUserName(username);
List<GrantedAuthority> authorities = buildUserAuthority(user.getRole());
return buildUserForAuthentication(user, authorities);
}
private User buildUserForAuthentication(com.sencerseven.springsecurityauth.dto.User user,
List<GrantedAuthority> authorities) {
return new User(user.getUsername(), user.getPassword(), user.isEnabled(), true, true, true, authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<Role> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
for (Role userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
}
List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);
return Result;
}
}
User.class
package com.sencerseven.springsecurityauth.dto;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
#Entity
#Table(name = "User")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String password;
private boolean enabled;
private String email;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(joinColumns = #JoinColumn(name = "user_id"), inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> role;
public User() {
}
public User(String username, String password, boolean enabled, String email, Set<Role> role) {
this.username = username;
this.password = password;
this.enabled = enabled;
this.email = email;
this.role = role;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Set<Role> getRole() {
return role;
}
public void setRole(Set<Role> role) {
this.role = role;
}
#Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + ", enabled=" + enabled
+ ", email=" + email + ", role=" + role + "]";
}
}
Role.class
package com.sencerseven.springsecurityauth.dto;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
#Entity
#Table(name = "Role")
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String role;
#ManyToMany(mappedBy = "role", fetch = FetchType.LAZY)
private Set<User> user;
public Role() {
}
public Role(String role, Set<User> user) {
this.role = role;
this.user = user;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public Set<User> getUser() {
return user;
}
public void setUser(Set<User> user) {
this.user = user;
}
#Override
public String toString() {
return "Role [id=" + id + ", role=" + role + ", user=" + user + "]";
}
}
if you use WebMvcConfigurationSupport and #AuthenticationPrincipal than you must add a AuthenticationPrincipalArgumentResolver:
public class WebMvcConfig extends WebMvcConfigurationSupport {
...
#Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthenticationPrincipalArgumentResolver());
}