Disable an action from RestController default behaviour - java

I recently started learning the sping-boot framework and I'm trying to build a controller to handle users.
I created a rest controller as follow:
#RestController
#RequestMapping("/users")
public class UserController {
#Autowired
UserRepository userRepository;
#Autowired
BCryptPasswordEncoder bCryptPasswordEncoder;
#PostMapping("/sign-up")
public void signUp(#RequestBody User user) {
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
userRepository.save(user);
}
}
and this is the model:
#Entity
#Table(name = "req_user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username;
#JsonIgnore
private String password;
private String email;
public User() { }
public User(String username, String password, String email) {
this.id = null;
this.username = username;
this.password = password;
this.email = email;
}
...
#JsonIgnore
public String getPassword() {
return password;
}
#JsonProperty
public void setPassword(String password) {
this.password = password;
}
...
}
end this is the repository:
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
User findByUsername(String username);
}
Now that works fine, but I want to disable some actions that are provided by
RestController by default. In particular, I want to inhibit the possibility to view the list of all users and to delete one of them. What is the recommended way to do that?

Related

#JsonIgnor not working on UserDetails class Java Spring

I'm trying to make a blog using spring boot java with auth.
I created User class the implements UserDetails, and Post class.
When using the path /posts I wish to see all the posts in the blog, problem is that each post contains creator (User obj) and it shows the password of the user - and this is what I'm trying to avoid.
I tried #JsonIgnor, #JsonProperty didn't work
Tried also #JsonProperty(access = Access.WRITE_ONLY) I get an error on the Access.WRITE_ONLY.
Does are the classes:
package com.example.blog.entities;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.persistence.*;
import java.util.Collection;
import java.util.List;
#Entity
#Table(name = "users")
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String username;
#JsonIgnore
private String password;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Role> roles;
public User() {}
public User(String username, String password, List<Role> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
#JsonIgnore
public String getPassword() {
return password;
}
#JsonProperty
public void setPassword(String password) {
this.password = password;
}
public Integer getId() {
return id;
}
}
import javax.persistence.*;
import java.time.LocalDate;
import java.util.Date;
#Entity
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String title;
private String body;
private LocalDate date;
#ManyToOne
private User creator;
public Post() {
}
}
import com.example.blog.entities.Post;
import com.example.blog.entities.User;
import com.example.blog.repositories.PostRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.List;
#Service
public class PostService {
private final PostRepository postRepository;
#Autowired
public PostService(PostRepository postRepository){
this.postRepository = postRepository;
}
public List<Post> getAllPosts(){
return postRepository.findAll();
}
public void insert(Post post) {
if(post.getBody() == null || post.getTitle() == null ){
throw new IllegalArgumentException("Missing args");
}
post.setDate(LocalDate.now());
postRepository.save(post);
}
public List<Post> getPostByUsername(User user){
return postRepository.findByCreatorId(user.getId());
}
}
The endpoint:
#GetMapping(value = "/posts")
public List<Post> posts(){
return postService.getAllPosts();
}
You should not expose your internal data model (JPA). Use transport classes. And you should remove the "#JsonProperty" from "public void setPassword(String password) ...". It is contradicting ("overriding") the "#JsonIgnore". And don't store your password as plaintext! Use for example jBCrypt.
My Setup:
public static class XUser {
private String username;
#JsonIgnore
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
//#JsonProperty
public void setPassword(String password) {
this.password = password;
}
}
#Test
public void testJson() {
XUser user = new XUser();
user.setPassword("oh shit!");
user.setUsername("name");
try {
ObjectMapper om = new ObjectMapper();
System.out.println(om.writeValueAsString(user));
} catch (Exception ex) {
ex.printStackTrace();
}
}
And the output:
{"username":"name"}

SpringBoot #Service annotation issue

Hi people I am working on one application .I have created a model but after giving all annotation and configuring all properties it is showing below error. Can anyone please look into below issue?
application.properties
spring.datasource.url = jdbc:mysql://localhost:3306/expenses
spring.datasource.username =dante
spring.datasource.password =jboss
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.format_sql=true
server.port=9191
Main Class
package com.expenses.demo;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.expenses.demo.modal.Role;
import com.expenses.demo.modal.User;
import com.expenses.demo.modal.UserRole;
import com.expenses.service.UserService;
#SpringBootApplication
public class ExpenseApplication implements CommandLineRunner {
#Autowired
private UserService userService;
public static void main(String[] args) {
SpringApplication.run(ExpenseApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
System.out.println("Starting code");
User user = new User();
user.setFirstname("Aniket");
user.setLastname("Turiley");
user.setEmail("abc#gmail.com");
user.setPassword("abc");
user.setPhone("99220289");
Role role1=new Role();
role1.setRoleId(44L);
role1.setRoleName("ADMIN");
Set<UserRole> userRoleSet = new HashSet<>();
UserRole userRole = new UserRole();
userRole.setRole(role1);
userRole.setUser(user);
userRoleSet.add(userRole);
User user1= this.userService.createUser(user,userRoleSet);
System.out.println(user1.getUsername());
}
}
Model Class
Role.java
package com.expenses.demo.modal;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name="roleinformation")
public class Role {
#Id
private long roleId;
private String roleName;
#OneToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY,mappedBy = "role")
private Set<UserRole> userRoles = new HashSet<>();
public Role() {
}
public Role(int roleId, String roleName) {
this.roleId = roleId;
this.roleName = roleName;
}
public long getRoleId() {
return roleId;
}
public void setRoleId(long l) {
this.roleId = l;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public Set<UserRole> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
}
User.java
package com.expenses.demo.modal;
import java.util.HashSet;
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.OneToMany;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
#Entity
#Table(name="usersinfo")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstname;
private String lastname;
private String username;
private String password;
private String email;
private String phone;
private boolean enable=true;
// user has many roles
#OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER,mappedBy = "user")
#JsonIgnore
private Set<UserRole> userRoles = new HashSet<>();
public User() {
}
public User(Long id, String firstname, String lastname, String username, String password, String email,
String phone, boolean enable) {
this.id = id;
this.firstname = firstname;
this.lastname = lastname;
this.username = username;
this.password = password;
this.email = email;
this.phone = phone;
this.enable = enable;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
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 isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public Set<UserRole> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
}
Repository Interfaces
RoleRepository
package com.expenses.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.expenses.demo.modal.Role;
public interface RoleRepository extends JpaRepository<Role, Long>{
}
UserRepository
package com.expenses.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.expenses.demo.modal.User;
public interface UserRepository extends JpaRepository<User, Long> {
public User findByUsername(String username);
}
Service Class
Service.java
package com.expenses.service;
import java.util.Set;
import com.expenses.demo.modal.User;
import com.expenses.demo.modal.UserRole;
public interface UserService {
//creating user
public User createUser(User user,Set<UserRole> userRoles) throws Exception;
}
Service Implementation class
ServiceImplementation.java
package com.expenses.service;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.expenses.demo.modal.User;
import com.expenses.demo.modal.UserRole;
import com.expenses.repository.RoleRepository;
import com.expenses.repository.UserRepository;
import com.expenses.service.UserService;
#Service
public class UserServiceImplementation implements UserService{
private UserRepository userRepository;
#Autowired
private RoleRepository roleRepository;
#Override
public User createUser(User user, Set<UserRole> userRoles) throws Exception{
User local= this.userRepository.findByUsername(user.getUsername());
if(local!=null) {
System.out.println("User Already Exist");
throw new Exception("User Already Exist");
}else {
// user create
for(UserRole ur:userRoles) {
roleRepository.save(ur.getRole());
}
user.getUserRoles().addAll(userRoles);
local = this.userRepository.save(user);
}
return local;
}
}
ERROR
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
[2m2021-07-28 18:16:59.304[0;39m [31mERROR[0;39m [35m8492[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mo.s.b.d.LoggingFailureAnalysisReporter [0;39m [2m:[0;39m
***************************
APPLICATION FAILED TO START
***************************
Description:
Field userService in com.expenses.demo.ExpenseApplication required a bean of type 'com.expenses.service.UserService' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.expenses.service.UserService' in your configuration.
Spring Boot will do the component scan (search for Classes with #Service, #Repository, #Controller, #Component) annotation only classes that are located in the same package as the main class (#SpringBootApplication annoteted class), and its subpackages.
So you need eighter to
move ExpenseApplication one package up, to com.expenses,
move all classes that needs to be found by the component scan to to com.expenses.demo or a subpackage, or
configure the component scan (and Spring Data too), for example, by #SpringBootApplication(scanBasePackages = "com.expenses")
BTW: Najeeb Arif is right too, in addition you need to add #Autowired to UserServiceImplementation.userRepository but I think you do not need to add the #Repository annotation to the Spring-Data-JPA repository interfaces.
Add this to your main class
#SpringBootApplication(scanBasePackages = "com.expenses")
This will help the component scan will find your classes.
First mark both of your Repositories with
#Repository
In your user service, you are missing the Autowired annotation.
I personally like the constructor injection.
Role Repository
#Repository
public interface RoleRepository extends JpaRepository<Role, Long>{
}
Same for the user repo.
in your User Service Impl
#Service
public class UserServiceImplementation implements UserService{
private final UserRepository userRepository;
private final RoleRepository roleRepository;
/* when using constructor injection #Autowired is not required */
public UserServiceImplementation(UserRepository userRepository, RoleRepository roleRepository){
this.userRepository = userRepository;
this.roleRepository = roleRepository;
}
#Override
public User createUser(User user, Set<UserRole> userRoles) throws Exception{
//...
}
}

How to register users with different roles and fields through a common UserDetailsService?

I have a superclass of User and its four descendants. Each heir corresponds to a specific role and has certain fields. I need user registration and authentication on such a database structure. I tried to do this via #Inheritance(JOINED), and it worked for normal CRUD operations, but there were problems with the registration and authentication.
I tried to do this through several UserDetailsService, #Configuration and #Order, but one configuration blocked the other, some requests did not work or UserDetails returned empty. There is something else with the authentication provider.
Is it possible to implement through it or is there a better suggestion to achieve this?
Thanks.
Parent class user and his descendants:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "usr", schema = "public")
#Inheritance(strategy = InheritanceType.JOINED)
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
#Transient
private String matchingPassword;
private String name;
private String surname;
private String patronymic;
#DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate birthday;
private String hometown;
private String number;
private String mail;
private String avatar;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "user_roles",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id")
)
private Set<Role> roles;
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return getRoles();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
#Entity
#Table(name = "student", schema = "public")
#Data
#EqualsAndHashCode(callSuper = true)
#ToString(callSuper = true)
#NoArgsConstructor
#AllArgsConstructor
public class Student extends User implements Serializable {
private String faculty;
private Integer rating;
#Builder
public Student(Long id,
String username,
String password,
String matchingPassword,
String name,
String surname,
String patronymic,
LocalDate birthday,
String hometown,
String number,
String mail,
String avatar,
Set<Role> roles,
String faculty,
Integer rating) {
super(id, username, password, matchingPassword, name, surname, patronymic, birthday, hometown, number, mail, avatar, roles);
this.faculty = faculty;
this.rating = rating;
}
}
#Entity
#Table(name = "director", schema = "public")
#Data
#EqualsAndHashCode(callSuper = true)
#ToString(callSuper = true)
#NoArgsConstructor
#AllArgsConstructor
public class Director extends User implements Serializable {
private String department;
#Builder
public Director(Long id,
String username,
String password,
String matchingPassword,
String name,
String surname,
String patronymic,
LocalDate birthday,
String hometown,
String number,
String mail,
String avatar,
Set<Role> roles,
String department) {
super(id, username, password, matchingPassword, name, surname, patronymic, birthday, hometown, number, mail, avatar, roles);
this.department = department;
}
}
UserService which implements UserDetailsService:
#Service
public class UserService implements UserDetailsService {
private final UserRepository userRepository;
private final FileService fileService;
#Value("${application.avatar-folder}")
private String avatarFolder;
#Autowired
public UserService(UserRepository userRepository,
#Lazy FileService fileService) {
this.userRepository = userRepository;
this.fileService = fileService;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if(user != null) {
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
for(Role role : user.getRoles()) {
grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
grantedAuthorities
);
}
throw new UsernameNotFoundException("Пользователя с именем " + username + " не существует!");
}
Spring Security configuration:
#Configuration
#EnableWebSecurity
#ComponentScan("com.amirdigiev.tsaritsynostudentportfolio")
#SuppressWarnings("Duplicates")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserService userService;
#Autowired
public SecurityConfig(UserService userService) {
this.userService = userService;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/registration")
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.loginPage("/login")
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/home", true)
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID");
http.headers()
.cacheControl().disable()
.and()
.csrf().disable();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/**", "/images/**");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(bCryptPasswordEncoder());
}
#Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
In the end, I decided to just add the User field (via composition) to all roles.

Springboot API returns empty response

I built a simple Springboot API which is hooked up to a H2 db that contains some test data. However when I hit the API endpoint I get an empty response.
[{}]
When I debug my application the user object that is returned by the controller contains the user I am expecting.
UserController.java
#RestController
#RequestMapping("api/user")
public class UserController {
private UserService userService;
public UserController(#Autowired UserService userService){
this.userService = userService;
}
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public Set<User> getAllUsers(){
final Set<User> users = userService.getAllUsers();
return users;
}
}
UserRepo.java
public interface UserRepository extends CrudRepository<User, Long> {
#Query("SELECT usr from User usr")
Set<User> getAllUsers();
}
UserService.java
public interface UserService {
Set<User> getAllUsers();
}
UserServiceImpl.java
#Service
public class UserServiceImpl implements UserService {
private final UserRepository repository;
public UserServiceImpl(#Autowired UserRepository userRepository){
this.repository = userRepository;
}
#Override
public Set<User> getAllUsers(){
final Set<User> users = repository.getAllUsers();
return users;
}
}
User.java
#Entity
#Getter
public class User {
#Id
private Long id;
private String username;
private String firstname;
private String lastname;
private String email;
private String role;
private String premium;
}
This was a rather strange issue of which I am still unable to say which. However, removing lombok's #getter and #setter annotations then implementing traditional ones fixed this issue.
You'll have to set the class members of User public to allow jackson serialise them, i.e.,
// User.java
#Entity
public class User {
#Id
public Long id;
public String username;
public String firstname;
public String lastname;
public String email;
public String role;
public String premium;
}
Note: if you'd like to not serialise a field, use #JsonIgnore instead of setting it as private, e.g.,
#Entity
public class User {
...
#JsonIgnore
public String role;
...
}
Just remove final and change Set to List as well.
and you really don`t need to do like this:
public UserController(#Autowired UserService userService)
Just remove this method and add Autowired up to userService filed.
Because final object can`t be cast to json string.
remove this as well:
produces = MediaType.APPLICATION_JSON_VALUE</h3>

I have an error in testing my simple spring mvc service

I create a new service with spring boot and spring mvc .
UserEntity.class:
#Entity
#Table(name = "users")
public class UserEntity {
private long id;
private String username;
private String password;
private boolean active;
private boolean login;
public UserEntity(UserDto dto) {
this.id = dto.getId();
this.username = dto.getUsername();
this.password = dto.getPassword();
this.active = dto.isActive();
}
// getters&setters...
}
UserDto.class:
public class UserDto {
private long id;
private String username;
private String password;
private boolean active;
public UserDto(long id, String username, String password, boolean active) {
this.id = id;
this.username = username;
this.password = password;
this.active = active;
}
// getters&setters...
}
UserRepository:
#Repository
public interface UserRepository extends JpaRepository<UserEntity, Long> {
}
UserServiceImpl.class: (and UserService Interface)
#Service
#Transactional
public class UserServiceImpl implements UserService {
private final UserRepository repo;
#Autowired
public UserServiceImpl(UserRepository repo) {
this.repo = repo;
}
#Override
public boolean saveUser(UserDto dto) {
UserEntity user = new UserEntity(dto);
repo.save(user);
return true;
}
}
UserController.class:
#RestController
public class UserController {
private final UserService service;
#Autowired
public UserController(UserService service) {
this.service = service;
}
#RequestMapping(value = "/users", method = RequestMethod.POST)
public void createUser(#RequestBody UserDto userDto) {
service.saveUser(userDto);
}
}
Application.class:
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
my Spring Boot project starts correctly. But when I test my service with IntelliJ Test Restful Web Service Tool I encounter an error:
Response:
{"timestamp":1464066878392,"status":405,"error":"Method Not Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/users"}
What is the problem?
My suggestion would be to remove the constructors from the UserController and UserServiceImpl classes, there's no need for them. Then, assign the #Autowired annotation to the declarations instead. Also, I don't think you need to make them final.
UserServiceImpl.class:
#Service
#Transactional
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository repo;
#Override
public boolean saveUser(UserDto dto) {
UserEntity user = new UserEntity(dto);
repo.save(user);
return true;
}
}
UserController.class:
#RestController
public class UserController {
#Autowired
private UserService service;
public UserController(UserService service) {
this.service = service;
}
#RequestMapping(value = "/users", method = RequestMethod.POST)
public void createUser(#RequestBody UserDto userDto) {
service.saveUser(userDto);
}
}

Categories